html_safe and helpers in rails 3 – Rails 2 vs 3
In Rails 3 (contrary to Rails 2) Strings are automatically escaped using
ERB::Util.h(string) and the reason is simple. In 95% of the cases you won’t have to print html code inside ruby strings like this:
In Rails 2 for this 95% of the cases you had to call the “h” helper to escape the output which was really annoying and insecure (if you forgot one).
Although this was the case for views, constructing a helper that prints html content became tricky in Rails 3. If you want your html content to stay unescaped it has to be an
ActiveSupport::SafeBuffer instance instead of a
String instance. To achieve this there are two solutions:
html_safe and helpers in rails 3 – constructing a helper
The first one is using html_safe method:
# helper.rb def foo html = "" html += "<strong>bar</strong>" html.html_safe end
This will output html correctly. A similar approach would be to use safe_concat inside your helper like this:
# helper.rb def foo safe_concat("<strong>bar</strong>") return end
In every case you can use
raw() view helper to keep your string unescaped:
# helper.rb def foo "<strong>bar</strong>" end
html_safe and helpers in rails 3 – the tricky part
I recently came up with this case:
#helper.rb def foo html = content_tag :p, "bar" html += "<strong>another bar</strong>" html.html_safe end
It’s output was something that I wasn’t expecting. The
<strong>tags were escaped while the
<p>tags remained unescaped. This made me suspicious of the concat method that
ActiveSupport::SafeBufferimplements, which is the following:
def concat(value) if value.html_safe? super(value) else super(ERB::Util.h(value)) end end
As you can see if the argument of concat is a String (html_safe? == false) the value will be escaped and then concated.
So if you want to concat
ActiveSupport::SafeBuffer instances always begin from a String instance even if it’s an empty string:
#helper.rb def foo html = "" html += content_tag :p, "bar" html += "<strong>another bar</strong>" html.html_safe end
This will do the job for you!
Thank you! This last bit about instancing an empty string first has helped me a lot!
Hey Thanks for this posts! It saved me a lot of time