Rails escapes HTML in my plain text mails - ruby-on-rails

I am using the rails 3.2.5 ActionMailer to send plain text mails. Given I have a mail view like this:
message_from_user.text.erb:
Hi <%= #recipient.name %>,
You got the following message from <%= #sender.name %>:
<%= #message %>
When #message is "quotes & ampersands", then the plain text mail contains "quotes & ampersands". So it seems like rails just treats this as a HTML view and escapes any html in order to prevent cross site scripting. However this is a plain text mail. The extension is .text.erb and ActionMailer detectes this and sets the MIME to text/plain. So I never want to escape any html in it.
I have quite a few mail templates in my application, they are all plain text. I would consider patching all of them to include <%=raw #message%> or <%= #message.html_safe %> bad style - not very DRY.
I tried varios work-arounds that included money patching Erubis. None of them seem to work. I am looking for some patch or config option or anything to disable escaping html for all .text.erb files.
Any help is greatly appreciated!

After some hours of debugging through the Erubis code, I found the following fix. You can just put it into config/initializers/fix_my_mails.rb. I've tested this with rails 3.2.7. It may work with other versions.
module ActionView
class Template
module Handlers
class ERB
def call(template)
if template.source.encoding_aware?
# First, convert to BINARY, so in case the encoding is
# wrong, we can still find an encoding tag
# (<%# encoding %>) inside the String using a regular
# expression
template_source = template.source.dup.force_encoding("BINARY")
erb = template_source.gsub(ENCODING_TAG, '')
encoding = $2
erb.force_encoding valid_encoding(template.source.dup, encoding)
# Always make sure we return a String in the default_internal
erb.encode!
else
erb = template.source.dup
end
self.class.erb_implementation.new(
erb,
:trim => (self.class.erb_trim_mode == "-"),
:escape => template.identifier =~ /\.text/ # only escape HTML templates
).src
end
end
end
end
end
It just disables HTML entities in every erb file containing .text in the file name.

Try
<%= #message.html_safe %>
You'd found this answer if you had used the search function. If that doesn't suit your needs, maybe check
https://rails.lighthouseapp.com/projects/8994/tickets/4858-actionmailer-is-html-escaping-ampersand-in-urls-in-plain-text-messages
If you haven't seen that yet, some options are discussed there

Related

Stripping HTML markup from a translation string

I have some translations that I use in my views. These translations sometimes return very basic HTML markup in them -
t("some.translation")
#=> "This is a translation with some markup<br />"
(Side note: I'm using the fantastic it gem to easily embed markup, and specifically links, in my translations)
What if I wanted to strip the HTML tags in certain cases, like when I'm working with the translation string in my RSpec tests. Is there an HTML strp functionality that will compile and remove that markup?
t("some.translation").some_html_strip_method
#=> "This is a translation with some markup"
Thanks!
You may want to try strip_tags from ActionView::Helpers::SanitizeHelper
strip_tags("Strip <i>these</i> tags!")
# => Strip these tags!
strip_tags("<b>Bold</b> no more! <a href='more.html'>See more here</a>...")
# => Bold no more! See more here...
strip_tags("<div id='top-bar'>Welcome to my website!</div>")
# => Welcome to my website!
Depending on where you use it.
strip_tags method not functioning in controllers, models, or libs
It comes up with an error about white_list_sanitizer undefined in the class you’re using it in.
To get around this, use:
ActionController::Base.helpers.strip_tags('string')
To shorten this, add something like this in an initializer:
class String
def strip_tags
ActionController::Base.helpers.strip_tags(self)
end
end
Then call it with:
'string'.strip_tags
But if you only need to use it in VIEW, simply:
<%= strip_tags(t("some.translation")) %>

Rails actionmailer escaping HTML with link_to

I am using Action Mailer and trying to include a link. For some reason the HTML is being escaped and, rather than showing a link, it is showing:
here
Instead it should just show the link. Here is the Ruby:
<%= raw(link_to("here", employer_url(:task_review => 'true'))) %>
I have also tried:
<%= link_to("here", employer_url(:task_review => 'true')).html_safe %>
and
<%= link_to("here", employer_url(:task_review => 'true')) %>
None of them seem to work. I've looked at other SO answers to similar questions and they all say to use either raw or html_safe, but neither work. Does anyone have any ideas?
From the description of your problem it looks like the problem is not in the template rendering, but in the content type.
An email client accepts different content types, and renders accordingly - parses and renders the HTML if the content type is text/html, or shows the text as-is if the content type is text/plain.
Many mailers send mail containing more than one version of the mail (one HTML and one TEXT), to support old mail clients which don't have HTML capabilities.
To check whether the mail your program sent has an HTML version, open its raw message (in Gmail that would be under More -> show original) and look for text looking like this:
------=_NextPart_001_0048_01CE7CA4.8389CCD0
Content-Type: text/html;
charset="windows-1255"
This means that there is an HTML version of the mail you sent.
If however, all you see is something like:
------=_NextPart_001_0048_01CE7CA4.8389CCD0
Content-Type: text/plain;
charset="windows-1255"
your problem is there. (if both options appear - your mail client may not support HTML)
If you find that you do not send an HTML version, make sure your template file has the extension .html.erb rather .text.erb (the latter indicates to the mailer that you want a text-only mail format).
in config/environments/development.rb
config.action_mailer.default_url_options = { :host => 'localhost:3000' }
This may solve the problem.
For ActionMailer you should build the URL with the url_for helper because other helpers like link_to are not available in ActionMailer, or include the helper methods in your ActionMailer class:
<%= url_for controller: 'login',
action: 'verify',
only_path: false,
host: 'http://myawesomesite.com',
params: { token: '12hew' } %>

How can I include an arbitrary file into a HAML template?

I want to have independent .markdown files that I then include in my haml templates. So I want to somehow include -- not render -- an external file into the template. I want the parent file to have :markdown in it, with the inclusion directly below that, and then the .markdown file to just be pure markdown.
Or: Is there a way to just use markdown as a rails template language (same way i can write templates or partials in erb or haml and rails just figures it out)?
This is similar to your solution, but using the :markdown filter. Haml does string interpolation on any filtered text, so you can read the markdown file like this.
:markdown
#{File.read(File.join(File.dirname(__FILE__), "foo.markdown"))}
You could put this into a helper, but you'd have to be careful with the file paths.
The simplest way I could think of is to create a custom template handler for Markdown. That you get to use Markdown code as partials (also getting support for locals for free).
module Markdown
class Template < ActionView::Template::Handler
include ActionView::Template::Handlers::Compilable
self.default_format = Mime::HTML
def compile(template)
'"' + Maruku.new(template.source).to_html + '".html_safe'
end
end
end
And then register it with markdown extension (in application.rb or custom initializer):
ActionView::Template.register_template_handler(:md, Markdown::Template)
And then user render like you would for any partial :)
# for file foo.md
= render 'foo'
Here's the best I can come up with (no haml filter involved at all):
=raw Maruku.new(File.read(File.dirname(__FILE__)+'/foo.markdown')).to_html
This is something I asked the HAML developers a while back. I suggested we needed an :include filter for HAML. Their response was we should load the file into a variable and then use the variable like we would any other.
Extending ActionView::Template::Handler is deprecated in at least Rails 3.1.0. Instead the following worked for me:
In lib/markdown_views.rb:
require "rdiscount"
class MarkdownViews
def call template
'md = ERB.new(<<\'EOF\'%s
EOF
).result( binding)
RDiscount.new( md).to_html.html_safe'% template.source
end
end
In config/application.rb:
require "markdown_views"
ActionView::Template.register_template_handler :markdown, MarkdownViews.new
In views/public/home.html.markdown:
# H1
+ Bullets.
+ screaming.
+ from out of nowhere
<%= "Embedded Ruby" %>

Rails 3: How to display properly text from "textarea"?

In my Rails 3 application I use textarea to let users to write a new message in a forum.
However, when the message is displayed, all newlines look like spaces (there is no <br />). Maybe there are other mismatch examples, I don't know yet.
I wonder what is the most appropriate way to deal with this.
I guess that the text that is stored in the database is OK (I see for example that < is converted to <), so the main problem is the presentation.
Are there build-in helper methods in Rails for this ?
(simple_format does something that looks similar to what I need, but it adds <p> tags which I don't want to appear.)
Rails got a helper method out of the box, so you dont have to write your own method.
From the documentation:
simple_format(text, html_options={}, options={})
my_text = "Here is some basic text...\n...with a line break."
simple_format(my_text)
# => "<p>Here is some basic text...\n<br />...with a line break.</p>"
more_text = "We want to put a paragraph...\n\n...right there."
simple_format(more_text)
# => "<p>We want to put a paragraph...</p>\n\n<p>...right there.</p>"
simple_format("Look ma! A class!", :class => 'description')
# => "<p class='description'>Look ma! A class!</p>"
You can use style="white-space: pre-wrap;" in the html tag surrounding the text. This respects any line breaks in the text.
Since simple_format does not do what you want, I'd make a simple helper method to convert newlines to <br>s:
def nl2br(s)
s.gsub(/\n/, '<br>')
end
Then in your view you can use it like this:
<%= nl2br(h(#forum_post.message)) %>
If someone still gets redirected here and uses Rails 4:
http://apidock.com/rails/v4.0.2/ActionView/Helpers/TextHelper/simple_format
You can now specify the tag it gets wrapped in (defaults to p) like so:
simple_format(my_text, {}, wrapper_tag: "div")
# => "<div>Here is some basic text...\n<br />...with a line break.</div>"
CSS-only option
I believe one of the easiest options is to use css white-space: pre-line;
Other answers also mentioned using white-space, but I think it needs a little more information:
In most cases you should probably choose pre-line over pre-wrap. View the difference here.
It's very important to keep in mind about white-space that you should not do something like this:
<p style="white-space: pre-line;">
<%= your.text %>
</p>
It will produce extra spaces and line-breaks in the output. Instead, go with this:
<p style="white-space: pre-line;"><%= your.text %></p>
HTML alternative
Another way is to wrap your text in <pre> tags. And last note on my CSS option is true here as well:
<p>
<pre><%= your.text %></pre>
</p>
Don't separate your text from <pre> tags with spaces or line-breaks.
Final thoughts
After googling this matter a little I have a feeling that html-approach is considered less clean than the css one and we should go css-way. However, html-way seems to be more browser-compatible (supports archaic browsers, but who cares):
pre tag
white-space
The following helper preserves new lines as line breaks, and renders any HTML or Script (e.g Javscript) as plain text.
def with_new_lines(string)
(h(string).gsub(/\n/, '<br/>')).html_safe
end
Use as so in views
<%= with_new_lines #object.some_text %>
I just used white-space: pre-line. So next line (\n) will render it.
You'll need to convert the plain text of the textarea to HTML.
At the most basic level you could run a string replacement:
message_content.gsub! /\n/, '<br />'
You could also use a special format like Markdown (Ruby library: BlueCloth) or Textile (Ruby library: RedCloth).
I was using Ace code-editor in my rails app and i had problem, that whenever i update or create the code, it adds always extra TAB on every line (except first). I couldn't solve it with gsub or javascript replace.. But it accidently solved itself when i disabled layout for that template.
So, i solved it with
render :layout => false

i18n on Ruby on Rails, < and > gets replaced by &gt ; &lt ; when not intended

I am creating locale files for internationalization in a rails app, and have a url that I want translated with tags included , for example
html.erb
<%= t(foo.bar.xxxx) %>
yml file
foo: bar:
xxxx: "xxxx"
result
&lt ;a href=
"/info/index.html"&gt ;xxxx</a&gt ;
which breaks my links. I do not have an h on the ruby part, so shouldn't this work?
Or should I just not have html tags within the yml file?
Rails version is 3.0.1
Ruby version is 1.8.7 p249
Your HTML YAML keys need to have a _html suffix:
foo:
bar:
xxxx_html: "<strong>Some HTML Here</strong>"
Doing this Rails will mark the string has html_safe and will render out the HTML instead of converting it to > and <.
You need to reference it with the full key name as well, Rails doesn't automatically see the _html suffix when you call xxxx.
<%= t 'foo.bar.xxxx_html' %>
Rails is preventing injection attacks by preventing model data from being displayed as actual markup. The raw function prevents that conversion.
Does
<%= raw t(foo.bar.xxxx) %>
work?

Resources