7

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!

1
  • I forgot to add a semicolon after myEmail declaration, but it's there in my actual code Commented Feb 3, 2016 at 10:45

3 Answers 3

4

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!

Sign up to request clarification or add additional context in comments.

27 Comments

This should work. I usually follow similar approach when dealing with the data that needs to be rendered in front-end. There are couple other ways that I am aware of, but this sure is the simplest of them all. +1
@v1p and the one that requires the least effort since it's effectively a oneliner to convert a ruby AR object to a JS object usable in view ;)
This isn't what i was asking, I'm already doing stuff like that here. (I had THAT problem a few weeks ago) my question was how to I extrapulate the content inside <%= javascript_tag do %> into a separate js file so it's less obtrusive (while still getting access to the @user from the initial GET request to show )
No need to do the round-tripping. Just do var user = <%= @user.to_json %>. It's already a JSON string, will be parsed by JS engine.
@SidneyLiebrand: you saw my PR, I take it? Also I was preparing pretty much the same edited post as you just did.
|
3
var user = <%= @user.to_json.html_safe %>;

Comments

0

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"];
});

See also Building a RESTful API in a Rails Application

3 Comments

Wouldn't I still need grab the @user.id in my .js to build the URL?
Well, that depends on what you are trying to do exactly. It is the same with a traditional html view. Here you also need to know the id before even being able to fetch the user from the database. So I don't really understand your question.
Best skip an unnecessary HTTP call

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.