I'm working on a rails app (4.1.8) that requires a lot of javascript in my show view, and I need a way to access data returned from ActiveRecord within the actual js file
Here's an example:
My Show controller
def show
@user = User.find(params[:id])
end
now i need to access this data in my show javascript, but this is the only way i could do it:
My Show view
<%= javascript_tag do %>
var myEmail = "<%= j @user.email %>";
// do stuff with myEmail
<% end %>
My question is, is there a way I can render this javascript or include it in a separate script tag while maintaining the userdata? I don't want to have to write hundreds of lines of jQuery and js inside this javascript_tag and it's painful to debug. Everything I've tried so far (putting it in the asset pipeline, rendering a seperate .js.erb file) just turns myEmail into a string with the ruby statement inside it. Any ideas? Thanks in advance!
-
I forgot to add a semicolon after myEmail declaration, but it's there in my actual coderhenvar– rhenvar2016年02月03日 10:45:42 +00:00Commented Feb 3, 2016 at 10:45
3 Answers 3
03-02-2016 21:10: Alright, got a working example - Dibbz to Sergio Tulentsev - he was right, parsing to valid JSON isn't even required, when calling .to_json on a ruby object it will print a valid JS object literal instead. (削除) Here is the github repo with working examples, if you'd like to clone it and use the code - feel free and have a nice day! (examples are built with Rails) (削除ここまで)
Aside from Øle Bjarnstroem's answer which implies the use of AJAX, if you want to use a model in JS you could do something like this
<% javascript_tag do %>
var user = <%= @user.to_json %>;
<% end %>
Now the JS variable user holds all the properties that the model has as well since it simply converts the ruby object (削除) to JSON (削除ここまで) directly to a JS object.
EDIT
As for not having to write the JS, you could create a helper for it - this would still inject the JS into your page but you could just supply an object as an argument to this function and then simply output that in your code with 1 call instead of doing the javascript_tag do ... end construct.
There are multiple ways to go about with this, you could use Rails' content_for to set and get content that will be rendered in your head.
e.g.
helper
module myHelper
def obj_as_js_var(var_name, obj, content_name = nil)
output_tag = javascript_tag("var #{var_name} = #{obj.to_json};".html_safe, type: 'text/javascript')
# if content_name is set, use content_for instead of directly printing the tag inline
if content_name
content_for content_name, output_tag
else
output_tag
end
end
end
Now when using this helper in your view
view
<%= obj_as_js_var('user', @user) %>
# ... rest of page
Will render the same output on a single line, the first argument ('user' in this case) is the name the variable will have, the second argument (@user) will be converted to JSON.
But wait a moment... what If I want it in the <head> of the document?
Well, the helper has an optional third argument which, if supplied will return the value of content_for and it will set the tag in the content.
So if, in your layout.erb you have something like
layout
<head>
<!-- ... snipped -->
<%= content_for :javascript if content_for? :javascript %>
</head>
You could use the following in your view instead (notice we're not rendering anything with <%= but using <% instead as we're saving the content for use in the <head>)
<% obj_as_js_var('user', @user, :javascript) %>
Now, the content_for :javascript in the head of your layout will render the output there, always. Note that if the content_for :javascript is loaded after the application.js then you won't have the data available there!
27 Comments
var user = <%= @user.to_json %>. It's already a JSON string, will be parsed by JS engine.var user = <%= @user.to_json.html_safe %>;
Comments
Why not provide the data you need via a simple REST API and just request it with jQuery and then do with the result whatever you want?
In your controller, for GET /users/:id/
class UsersController < ApplicationController
def show
@user = User.find(params[:id])
render json: @user
end
end
In jQuery:
$.getJSON( "/users/1", function( data ) {
// Do something with the retrieved data
console.log(data);
var myEmail = data["email"];
});