Forcing HTML Escaping in Rails 3 - ruby-on-rails-3

I'm running into an issue with the rails auto-escaping. It currently thinks a string is html_safe (which it is), but for display purposes I need it to still escape the html. Here's the steps the string is taking.
my_string = render(:partial => "set_string", :locals => {:item => #item})
<%= my_string %>
and the partial is basically
<h2>Page Header</h2>
<strong><%= item.name %></strong>
<%= item.body %>
etc
My understanding is that because I'm displaying text in a view directly (the h2, etc) it assumes it is safe, and it also properly escapes the item outputs, which makes the whole my_string safe. So, when I try to display it with the
<%= my_string %>
It doesn't escape the remaining html. I tried adding h to force the escaping but that didn't work.
So my question is, is there anyway to force html escaping of a safe string other than calling something on the string that will make it unsafe?
Thanks a lot for your help.

Escape from ActiveSupport::SafeBuffer in Rails 3+
In this instance <%= my_string.to_str %> will double-escape as required.
SafeBuffer workings
When a string is escaped by Rails you get an ActiveSupport::SafeBuffer. From that point, extra escaping is skipped because the SafeBuffer is html_safe?. It's a clever solution! There are times though, that we wish to escape such cleverness.
Why double-escape?
I needed to re-escape content generated by tag helpers to pass generated markup to data- attributes. This has also come in handy for displaying template-generated code.
Force-escape for a String that's html_safe?
Call to_str on the SafeBuffer, which returns a String.
# Example html safe content
content = content_tag :code, 'codez<>'
content.html_safe? # true
# call .to_str
escaped = content.to_str
escaped.html_safe? # false
# The escaped String will now be re-escaped when used in a template
The to_s gotcha
The to_s method looks very much like the to_str method.
Don't use to_s here, ActionView::SafeBuffer#to_s just returns self, where to_str is called above the SafeBuffer context, returning a naturally unsafe String.

Thanks to Sebastien for the suggestion, I wanted to get the real answer here and not buried in the comments:
I looks like this works:
<%= raw CGI::escapeHTML(my_string) %>
You need the "raw" call otherwise the escapeHTML makes the string unsafe in addition to escaping it so the auto escape double escapes it.

To interpret the html (it's what i understood you need), you have to use :
<%= raw my_string %>

Related

How do you spec an overridden Rails 3 FormHelper?

I have overridden the standard Rails FormHelper to get it to spit form elements out in our (pretty much Bootstrap-based) format (after http://www.likeawritingdesk.com/posts/very-custom-form-builders-in-rails).
It works fine, but it is difficult to write a spec for. I am using a spec like this:
rendered_form = helper.my_custom_form_for(#account, :url => '/accounts') do |f|
f.inputs do
# This isn't rendered
f.text_field 'name', :size => 30
# This is rendered
f.select 'locale', options_for_select([%w(Australia en-AU), %w(UK en-GB)])
end
end
What is rendered includes the select tag, but not the text field tag. I suspect this is because of the way ActionView handles blocks now, appending the return value of the block rather than the return value of each statement in the block. Obviously, when used in context in an app, the helper method gets passed some ERB and evaluates in that context.
Am I right that it's not possible to test rendering helper methods in this way, with multiple statements in a block?
If I am right, what would be the least hacky way of making a spec that does the same thing as the helper does in the context of a full app? Make an ERB string and somehow pass it to the helper to render?
Did you solve this? I am curious if you are just getting the last statment in the block returned. Have you tried changing the f.text_field/f.select order to see what gets returned? If so, then you just need to add them:
rendered_form = helper.my_custom_form_for(#account, :url => '/accounts') do |f|
f.inputs do
f.text_field('name', :size => 30) +
f.select('locale', options_for_select([%w(Australia en-AU), %w(UK en-GB)]))
end
end

Ruby/Rails - Is there an easy way to make hard-coded HTML symbols html_safe?

In my view I want to display some right double angle quotes in my link.
Before Rails 3, this worked:
<%= link_to "» #{#category.name}", some_path %>
Now what should I do if I want to specify the » as html_safe but not the rest of the link's text?
In other words I do not want to do this:
<%= link_to "» #{#category.name}".html_safe, some_path %>
I do not want the #category.name treated as html_safe.
This produces the desired result:
<%= link_to "»".html_safe + " #{#category.name}", some_path %>
However, if I do this:
<%= link_to "#{#category.name}" + "»".html_safe, some_path %>
The output of the angle quotes is not treated as safe. I see » on my page and not ».
Why?
I tried extracting "»".html_safe to a helper method with the same results.
Is there a way to easily designate hard coded text/symbols as HMTL safe in Rails 3?
Thanks.
In this situation I often explicitly escape the unsafe part:
"» #{h #category.name}".html_safe
you need to make sure that the whole string is html_safe...
I'd recommend to try this:
"» #{h #cagegory.name}".html_safe

How to make rails 3 I18n translation automatically safe?

I use rails 3. Is there any easy way to tell I18n to respect 'html safness' of string used in interpolation and make all translated string html safe by default? So if I have this en.yml:
en:
user_with_name: 'User with name <em>%{name}</em>'
and I use t('user_with_name', :name => #user.name), I get users name html escaped, but <em> and </em> is left as is?
http://guides.rubyonrails.org/i18n.html#using-safe-html-translations
The official Rails guide says you can use the interpolated variables without concern, since they are html escaped automatically, unless you specifically declare them to be String.html_safe.
From the guide:
Interpolation escapes as needed though. For example, given:
en:
welcome_html: "<b>Welcome %{username}!</b>"
you can safely pass the username as set by the user:
<%# This is safe, it is going to be escaped if needed. %>
<%= t('welcome_html', username: #current_user.username %>
Safe strings on the other hand are interpolated verbatim.
Change the name from user_with_name to user_with_name_html, then rails will know you have included html in the text.
Old question, but if someone wants to achieve this, here's the monkey patch I came up with :
module ActionView
module Helpers
module TranslationHelper
private
def html_safe_translation_key?(key)
true
end
end
end
end
Put this in an initializers and that's it!
Works with Rails 3.2.6.
Only marks the text in localization files as safe, not the interpolation parameters.

Rails3: how to disable automatic conversion of HTML tags?

How can I disable automatic conversion of HTML tags in Rails3? I have output in some controller view. For example I have method which outputs simple HTML link set..
[:en, :de].map{ |locale| link_to locate.to_s.upcase , { :locale => locate } ...
In view I'm calling my method <%= my_method %>
As a result I get this:
| <a href="/login?class=language_selected&amp;locale=en">EN</a>
How can I disable it?
I haven't worked with Rails3 so no guarantees. but it looks like this has to do with the fact that your method returns a list.
Rails will usually format internal data structures for output by escaping the special characters and displaying the html escaped interpretation of your data.
Try tacking a .join onto the end of your map call to return a string
[:en, :de].map{ |locale|
link_to locate.to_s.upcase , { :locale => locate }
...
}.join("<br/>")
Also rwilliams aka r-dub's suggestion to use raw will probably be necessary addition to this code. raw on a list however may give you an undesirable result probably because of an internal to_string call. Which is an implicit join(""). So add the raw to the method call in addition to returning a string.
<%= raw my_method %>
If you're sure your methods output is safe then you can use the raw method.
<%= raw my_method %>

escape HTML output but no line-breaks

I have a description text field in my Model.
No I want to add this description on the show page.
But the text renders ugly because of no linebreaks.
If i replace them with <br/> then the rails escape them with.
So i tried to use the raw() method.
I want to escape bad HTML but have the linebreaks in my output.
I end up with some ugly code.
raw(h(#place.description.gsub("\n","#linebreak#")).gsub("#linebreak#","<br/>"))
Do you have any suggestions?
you should use the simple_format helper:
<%= simple_format #place.description %>
http://api.rubyonrails.org/classes/ActionView/Helpers/TextHelper.html#method-i-simple_format
3 years later, but it's never too late to provide a good working solution
This will escape all HTML chars but the newlines (compatible Linux, Windows and Mac)
html_escape(#place.description).gsub(/(?:\n\r?|\r\n?)/, '<br />').html_safe
is what you are looking for
#place.description.html_safe.gsub("\n", '<br/>')
? But on second thought, doesn't the html_safe usage like that make it easy for the site to get XSS attack? (because it assumes the description is safe).
So won't a better solution be
<%= (h #place.description).gsub("\n", '<br/>') %>
at first I thought
<%= (h #place.description).gsub("\n", '<br/>'.html_safe) %>
is needed but actually both versions work. I then tested by adding some HTML tags to description and it got escaped into < etc, so it does prevent XSS attack.
Here's a solution that works:
<%= sanitize(#place.description.gsub("\n", "<br />"), :tags => %w(br), :attributes => %w()) %>
More reading:
Parsing newline characters in textareas without allowing all html tags
Documentation:
http://api.rubyonrails.org/classes/ActionView/Helpers/SanitizeHelper.html
From sanitize:
This sanitize helper will html encode all tags and strip all attributes that aren’t specifically allowed.
It also strips href/src tags with invalid protocols, like javascript: especially. It does its best to counter any tricks that hackers may use, like throwing in unicode/ascii/hex values to get past the javascript: filters. Check out the extensive test suite.
You can specify allowed tags with :tags option, and attributes with :attributes option.