10

I'm trying to embed model data in some javascript in my RoR 4 app. The controller is generating JSON for the model data like so...

def my_controller_method
  @person = Person.find(params[:id])
  @person_json = @person.to_json(only: [:name, :id])
end

and I'd like to use that json in my unobtrusive javascript to create javascript objects using JSON.parse()...

var personJSON = <%= j @person_json %>;
var person = JSON.parse(personJSON);

but the javascript that's generated is...

var personJSON = {\&quot;id\&quot;:1,\&quot;name\&quot;:\&quot;fred\&quot;};
var person = JSON.parse(personJSON);

and the javascript is failing silently.

When searching for a solution, I found this question asked on SO, but when I try to use the html_safe method, my rails app crashes saying html_safe is an unknown method.

Thanks in advance for your help!

Community
  • 1
  • 1
BeachRunnerFred
  • 18,070
  • 35
  • 139
  • 238

5 Answers5

25

What about this:

var personJSON = <%= @person_json.to_json.html_safe %>

or

var personJSON = <%= raw @person_json %>

I think the last option is better for your particular case.

rogelio
  • 1,541
  • 15
  • 19
  • Thanks, this fixed the problem. I had to wrap it in a escape_javascript call to work. Question, is this susceptible to XSS attacks? – BeachRunnerFred Oct 06 '14 at 23:29
  • from rails 3.x there is a concept of HTML-safe strings. `raw` transforms the object to string and then call `html_safe` – rogelio Oct 06 '14 at 23:45
  • This article explains that using `raw` alone is susceptible to XSS attacks: http://jfire.io/blog/2012/04/30/how-to-securely-bootstrap-json-in-a-rails-view/ – BeachRunnerFred Oct 06 '14 at 23:51
  • read this article too: http://www.jasonwieringa.com/Learning-About-XSS-Attacks-in-Rails/ – rogelio Oct 07 '14 at 00:08
1

You need to escape the JSON with escape_javascript:

var personJSON = "<%= escape_javascript @person_json %>";

You can also shorten this to:

var personJSON = "<%= j @person_json %>";
infused
  • 24,000
  • 13
  • 68
  • 78
  • thank you. When I do that, my app crashes with the error `ActionView::Template::Error (undefined method `gsub' for {"id"=>1, "name"=>"fred"}:Hash):`. Your thoughts? – BeachRunnerFred Oct 06 '14 at 22:59
  • `as_json` returns a Hash, not JSON. Use `to_json(only: [:name, :id])` instead. – infused Oct 06 '14 at 23:01
  • Ok, that makes the crash go away, but the resulting js code is still `var personJSON = {\"id\":1,\"name\":\"fred\"};`, which is causing the javascript to fail silently. – BeachRunnerFred Oct 06 '14 at 23:06
  • Oh, you need quotes around the string too. I will update the answer. – infused Oct 06 '14 at 23:19
  • Good catch! Still not working though. It throws an exception when parsed, the exception is "Unexpected token &". Thanks again for your help! – BeachRunnerFred Oct 06 '14 at 23:25
1

Works great on my rails 5.0

Controller

# foo.rb
@data = [{key1: 'value1', key2: 'value2'}, {key3: 'value3'}]

View

# foo.js.erb
var arr = JSON.parse("<%= escape_javascript(render(inline: @data.to_json)) %>")
console.log(arr) # (2) [Object, Object]
Ray Lee
  • 111
  • 1
  • 2
0

I like to use Jbuilder so in that case I used to do something like this:

var data = JSON.parse("<%= j raw render template: '/account/budget_item_elements/show.json.jbuilder' %>");

In show.json.jbuilder I could have:

json.extract! @budget_item_element, :id, :name, :created_at, :updated_at
joselo
  • 681
  • 1
  • 7
  • 9
0

I was trying to conditionally render text that only had some text in double quotes and this ended up being my solution

<%= is_true ? raw(%(This is text not in quotes: "#{@foo.bar.name}")) : "" %>

This is a smorgasbord of a lot of other stack overflow posts that when combined end up working for me.

Matt B
  • 1
  • 1