Mange / roadie

Making HTML emails comfortable for the Ruby rockstars
MIT License
1.34k stars 85 forks source link

How to have Roadie ignore URl rewriting? #98

Closed Dottenpixel closed 9 years ago

Dottenpixel commented 9 years ago

I'm using Roadie gem to generate liquid templates that I then plugin to my email marketing app. So, I've got lines in my html like: <img src="{{ line | img_url: 'small' }}" /> but, after document.transform that img tag becomes: <img src="%7B%7B%20line%20%7C%20img_url:%20'small'%20%7D%7D" style="border:0">

Is there a way to have Roadie ignore rewriting URLs altogether, or specifically for img[src]

Mange commented 9 years ago

I don't think that's really possible, I'm afraid. Roadie assumes you want to send valid HTML when you deliver an email, so it will properly encode everything when the DOM is serialized. I cannot really cause the DOM serialization in Nokogiri to ignore certain parts automatically.

The best work-around would probably be to transform the HTML string manually after Roadie is done. Something like this:

def restore_liquid_tags(html)
  html.gsub(LIQUID_TAG_MATCHER, LIQUID_TAG_REPLACEMENTS)
end
LIQUID_TAG_REPLACEMENTS = {
  "%7B" => "{",
  "%7D" => "}",
  "%20" => " ",
  "%7C" => "|",
}.freeze
LIQUID_TAG_MATCHER = Regexp.parse(LIQUID_TAG_REPLACEMENTS.keys.map { |key| Regexp.escape(key) }.join("|")).freeze

This is, of course, not a solution that works in the general case, but maybe it works in your specific views. You might need to make the matchers more specific, only matching inside tags or something.

Do you think this would work for you?


Here's how to use my example method on vanilla Roadie:

html = restore_liquid_tags doc.transform(html)

...and here's how to do it with roadie-rails:

email = MyMailer.my_mail
email.html_part.body = restore_liquid_tags(email.html_part.body.decoded) # if multi-part
# email.body = restore_liquid_tags(email.body.decoded) # if html only
Dottenpixel commented 9 years ago

@Mange Thank you for the quick and thorough reply. This works great!

One correction I had to make for it to work for me:

LIQUID_TAG_MATCHER = Regexp::new(LIQUID_TAG_REPLACEMENTS.keys.map { |key| Regexp.escape(key) }.join("|")).freeze
Mange commented 9 years ago

Glad it worked out for you. :-)

tors 13 nov 2014 20:52 Dottenpixel notifications@github.com skrev:

@Mange https://github.com/Mange Thank you for the quick and thorough reply. This works great!

One correction I had to make for it to work for me:

LIQUID_TAG_MATCHER = Regexp::new(LIQUID_TAG_REPLACEMENTS.keys.map { |key| Regexp.escape(key) }.join("|")).freeze

— Reply to this email directly or view it on GitHub https://github.com/Mange/roadie/issues/98#issuecomment-62954893.

kriskhaira commented 8 years ago

I'm having a problem with this solution. I'm trying to render an email in a controller but I keep getting an error.

Controller:

  email = MarketingMailer.my_email(big_shot_id, preview, inline)
  render html: restore_edm_tags(email.body.decoded)

  def restore_edm_tags(html)
    html.gsub(EDM_TAG_MATCHER, EDM_TAG_REPLACEMENTS)
  end
  EDM_TAG_REPLACEMENTS = {
    "%7B" => "{",
    "%7D" => "}",
    "%20" => " ",
    "%7C" => "|",
  }.freeze
  EDM_TAG_MATCHER = Regexp::new(EDM_TAG_REPLACEMENTS.keys.map { |key| Regexp.escape(key) }.join("|")).freeze

Template:

%img{src: "{{EMAILPART4.IMAGEURL}}", height: "auto", width: "100%", alt: "Offer Image"}

Error:

Roadie::InvalidUrlPath (Cannot use path "{{EMAILPART4.IMAGEURL}}" in URL generation. Caused by: bad URI(is not URI?): {{EMAILPART4.IMAGEURL}})

Mange commented 8 years ago

Hmm, that's a bit more complicated. You'd basically have to replace the <img> tag itself so you don't trigger URL inlining. Depending on your threshold for hackish solutions, maybe you'd like one of the following:

  1. Replace <img with <template-img in your views. Correct them using gsub / Nokogiri / some other HTML/XML library.
    • Roadie will then not trigger any inlining on them, but it won't add any styles using img either.
  2. Replace entire src with something else, then replace it. <img src="http://placeholder/EMAILPART4.IMAGEURL"
    • You probably need a proper HTML/XML library to handle this safely, but a regex could also work.
  3. Replace specific instances with more hard-coded replacements: EMAILPART4.IMAGE can be replaced with the fully rendered HTML using gsub
    • This will of course not help you inline anything on/using it.
  4. Stop using URL rewriting entirely by setting url_options to nil or false.
    • If this is in a roadie-rails mailer, you can disable it for specific emails without having to do it on any other email.
  5. It's high time to add some way of ignoring bad URLs.
    • Pull requests that add a ignore_bad_urls option would be welcome. It just needs to not raise when that is set and skip the problematic elements.

Sorry I can't be of more assistance right now.

kriskhaira commented 8 years ago

Thanks, @Mange. One question—what is it that I'm doing differently from the OP that it's complicated and I have to use one of the solutions?

Mange commented 8 years ago

My guess is that you are using url rewriting, while OP does not. OP's problem is that the stuff in the url is encoded, but the URLs are never parsed (as that would trigger your error).

Den ons 25 maj 2016 05:34Kris Khaira notifications@github.com skrev:

Thanks, @Mange https://github.com/Mange. One question—what is it that I'm doing differently from the OP that it's complicated and I have to use one of the solutions?

— You are receiving this because you were mentioned.

Reply to this email directly or view it on GitHub https://github.com/Mange/roadie/issues/98#issuecomment-221464798