Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Accessing Ruby objects in javascript

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!

like image 940
rhenvar Avatar asked Mar 14 '23 10:03

rhenvar


1 Answers

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.

  • Rails to_json

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!

like image 128
SidOfc Avatar answered Mar 19 '23 11:03

SidOfc