Why escape_javascript before rendering a partial?

I'm looking at this Railscast episode and wondering why the call to escape_javascript is needed here:

$("#reviews").append("<%= escape_javascript(render(:partial => @review)) %>");

What is escape_javascript used for?

According to the Rails docs:

escape_javascript(javascript)

Escape carrier returns and single and double quotes for JavaScript segments.

But that doesn't mean much to me.


Solution 1:

It's easier to understand if you split the code in two parts.

The first part $("#reviews").append("<%= ... %>"); is javascript with erb. This means that the <%= ... %> will be replaced by whatever the ruby code inside of it returns. The result of that replacement must be valid javascript, otherwise it will throw an error when the client tries to process it. So that's the first thing: you need valid javascript.

Another thing to take into account is that whatever ruby generates must be contained inside a javascript string with double quotes - notice the double quotes around the <%= ... %>. This means that the generated javascript will look like this:

$("#reviews").append("...");

Now let's examine the ruby part inside the <%= ... %>. What does render(:partial => @review) do? It is rendering a partial - which means that it could be rendering any kind of code - html, css ... or even more javascript!

So, what happens if our partial contains some simple html, like this one?

<a href="/mycontroller/myaction">Action!</a> 

Remember that your javascript was taking a double-quoted string as a parameter? If we simply replace the <%= ... %> with the code of that partial, then we have a problem - immediately after the href= there is a double quote! The javascript will not be valid:

// Without escaping, you get a broken javascript string at href
$("#reviews").append("<a href="/mycontroller/myaction">Action!</a>");

In order for this not to happen, you want to escape these special characters so your string is not cut - you need something that generates this instead:

<a href=\"/mycontroller/myaction\">Action!</a>

This what escape_javascript does. It makes sure that the string returned will not "break" javascript. If you use it, you will get the desired output:

$("#reviews").append("<a href=\"/mycontroller/myaction\">Action!</a>")

Regards!

Solution 2:

users may post malicious code (malicious users) that if left unescaped will potentially get executed, allowing users to control your application.

try this:

<% variable = '"); alert("hi there' %>
$("#reviews").append("<%= variable %>");

not really familiar with the syntax of rails, but if you don't escape variable then an alert box will show, and i dont think that is intended behaviour.