Rails raw vs html_safe
- 5 minsRails has some neat security protections out of the box. Rails will automatically escape html using html_escape method under the box, hence preventing execution of malicious code. But, in a real world scenario there are a lot of time where you want to render html that is not escaped. In that scenario two of the most used methods are raw and html_safe. In this article lets explore difference between this two methods.
What is XSS(Cross-Site Scripting) ?
XSS allows an attacker to execute scripts in the security context of your web application. The OWASP Top 10 of most frequent vulnerabilities lists it as #3, with other types of injection on #1 now.
You can read more about it here!
The playground app
rails new welcome
cd welcome
rails g controller welcome index
touch app/models/greeting.rb
I created basic rails app called welcome and added welcome controller with index view. Also, I added simple class Greeting in our models dir, this class I’m going to use for showing basic greeting message.
OK, still a few things to setup:
1.Add root route to config/routes.rb and delete everything else from class (thanks Rails 5 for removing this bloating comments in generated files :))
Rails.application.routes.draw do
root "welcome#index"
end
2.Add greeting message to Greeting model
class Greeting
def message
"Welcome jedi master"
end
end
3.Add Greeting model instance variable to WelcomeController
class WelcomeController < ApplicationController
def index
@welcome = Greeting.new
end
end
4.Show message on the root page (welcomes/index page)
<p><%= @welcome.message %></p>
Finally run your rails server got to localhost:3000, and you will see following rendered on root page.

Rendering html in view
Now lets emphasis Jedi Master title in our greeting message
class Greeting
def message
"Welcome <strong>jedi master</strong>"
end
end
Refresh your page and you will see that rails automatically escaped your content.

I trust my content don’t escape it Rails
Ok, you can used following methods to tell rails not to escape your content, both will produce same output
in app/views/welcomes/index.html.erb
<p><%= @welcome.message.html_safe %></p>
or
<p><%= raw @welcome.message %></p>

me:
Look yoda master I’m giving big respect by greeting all jedis properly!
yooda:
Why do you have two different methods for the same thing. Which path is the right path to choose, young apprentice ?
Rails raw() vs html_safe() method
html_safe() returns instance of SafeBuffer which inherits from String overriding +, concat and << so that:
- If the string is safe (another
SafeBuffer), the buffer concatenates it directly - If the string is unsafe (a plain
String), the buffer escapes it first, then concatenates it
You can look at the implementation here
raw() is a wrapper around html_safe() that forces the input to String and then calls html_safe() on it. It’s also the case that raw() is a helper in a module
Basically, you can simulate raw in out example like this
class Greeting
def message
"Welcome <strong>jedi master</strong>".to_s.html_safe
end
end
The main reason to use raw instead of html_safe if when content can be nil.
If you call html_safe on Nill class, like this
nil.html_safe
app fill fail saying undefined method `html_safe' for nil:NilClass.
But if you call raw on Nil class, app will not fail it will return instance of empty string, since calling nil.to_s returns new empty_string ""
Summary
- If a plain String is passed into a <%= %>, Rails always escapes it
- If a SafeBuffer is passed into a <%= %>, Rails does not escape it. To get a SafeBuffer from a String, call html_safe on it. The XSS system has a very small performance impact on this case, limited to a guard calling the html_safe? method
- If you use the raw helper in a <%= %>, Rails detects it at compile-time of the template, resulting in zero performance impact from the XSS system on that concatenation
- Rails does not escape any part of a template that is not in an ERB tag. Because Rails handles this at template compile-time, this results in zero performance impact from the XSS system on these concatenations
- If you have string which can be nil consider using
raw()becausehtml_safe()will throw an error
Be carefull not to let sits inject malicouse dark force to young jedis