mike0416
mike0416

Reputation: 461

Rails 4 getting local variable to js.erb file

I've read/researched other answers, but I can't get this to work. I have a js.erb file that is rendering a partial. I'm looking to pass a @node variable to it but I get an error in the console NameError: - undefined local variable or method "node" for #<#<Class:0x007fdcd9163510>:0x007fdcd813b728>

I'm not sure why it won't grab it.

_node.html.erb (node is a local variable in this partial):

<div id="tagged_users">
  <%= render partial: "nodes/user_tag_list", locals: { node: node } %>
</div>

partial that I would also like rendered in js.erb

_user_tag_list.html.erb:

<ul>
  <% node.tagged_users.map(&:name).each do |tag| %>
    <li><%= tag %>
      <%= link_to "x", node_path(node, remove_tag: tag), method: :patch %>
    </li>
  <% end %>
</ul>

node#update controller action:

def update
  @node = Node.find(params[:id])

  if params.fetch(:node, {}).fetch(:autocomplete_tag_names, false)
    tag = params[:node][:taggable_email]
    @node.user_tag_list.add(tag)
    @node.save

      respond_to do |format|
        format.js { render 'user_tag_add.js.erb' }
      end
    elseif
      # ...
    else
    # ...
  end

and finally, the js.erb file:

user_tag_add.js.erb:

$("#tagged_users").html("<%= escape_javascript(render 'user_tag_list', locals: { node: @node }) %>");

A couple of notes. The logic is sound. If I replace the html with a string rather than the partial it works fine. Also, if I binding.pry I can set node to @node without issue. Just can't get the @node to pass to node within the js.erb file.

EDIT

Here's the form partial, if useful:

<%= form_for node, remote: true, html: { class: "edit_node tag-users" } do |f| %>
  <%= f.label :autocomplete_tag_names %>
  <%= f.text_field :autocomplete_tag_names, data: { autocomplete_source: users_path }, value: nil %>
  <%= f.hidden_field :taggable_email, value: nil %>
  <%= f.submit %>  
<% end %>

Upvotes: 3

Views: 5145

Answers (1)

mike0416
mike0416

Reputation: 461

Ugh, it wasn't the variable scope at all. In my js.erb file above I originally had:

$("#tagged_users").html("<%= escape_javascript(render 'user_tag_list', locals: { node: @node }) %>");

Notice that above I said user_tag_list was a partial? Well, I didn't specify that in my render statement. I needed to modify the code to the following:

$("#tagged_users").html("<%= escape_javascript(render partial: 'user_tag_list', locals: {node: @node}) %>");

Then it worked. If anyone else is having issues debugging this type of code to see if it's the variable or not, I went through the following steps creating console messages:

  1. Make sure the variable can be seen

    console.log("<%= @node %>"); response: #&lt;Node:0x007fdcd8203138&gt;
    
  2. To confirm I wrote a couple of console statements that would extract something out of the object to make sure the correct information was being captured

    console.log("<%= @node.id %>"); response: 49
    console.log("<%= @node.name %>"); response: 'Test 2'
    

Once I saw that the variable was being passed I knew this wasn't the issue, and it looked to make sure I had my render statement properly formatted. Missing partial was a big mistake that cost me a few hours of my life. I hope this post saved got you some time back.

Additional Info

One other thing I learned while debugging this: If you ever want to set a local variable rather than an instance variable (for whatever reason I'm not sure) you can create it in your render statement within your controller action

respond_to do |format|
    format.js { render 'user_tag_add.js.erb', locals: {node: @node} }
end

Then you could do something like this within your js.erb file

console.log("<%= node %>")

Upvotes: 8

Related Questions