Javascript – Rails 4: Passing a local variable to a js.erb file from a partial containing a form_for helper

ajaxjavascriptjqueryruby-on-railsruby-on-rails-4

How do I pass a local variable from a form_for helper to a js file?

I have the following file called _subscribe.html.erb

<%= form_for @subscription, :url => {:controller => "subscriptions", :action => "create"} do |f| %>
  <div><%= hidden_field_tag :group_id, group.id %></div>
  <%= f.submit "Subscribe", class: "btn btn-primary subscribe_btn" %>
<% end %>

The group local variable gets passed from a do block into this form and works (html only up until now). I want to turn this into an ajax call so i added remote: true to the form and added the file create.js.erb to the subscriptions folder:

$("#new_subscription").html("<%= escape_javascript(render('subscriptions/unsubscribe', locals: { group: group } )) %>")

and this is my subscriptions controller create action:

def create
    @subscription = current_user.subscriptions.create(:group_id => params[:group_id])
    @subscription.save
      respond_to do |format|
      format.html { redirect_to groups_path, flash[:success] = "You have successfully subscribed to this group" }
      format.js  
    end
  end

However now I get this error:

ActionView::Template::Error (undefined local variable or method `group' for #<#<Class:0x007fe7ecfd4950>:0x007fe7ecfde7e8>):
    1: $("#new_subscription").html("<%= escape_javascript(render('subscriptions/unsubscribe', locals: { group: group } )) %>")
  app/views/subscriptions/create.js.erb:1:in `_app_views_subscriptions_create_js_erb__3184685282411376061_70317032458920'
  app/controllers/subscriptions_controller.rb:8:in `create'

The group local variable is not being passed from the form_for to the create.js.erb on submit. I have tried everything in the past 4 hours but am still coming up short. How do I fix this issue and pass the local variable from the _subscribe.html.erb partial to the create.js.erb file?

Edit:

More code… first my subscriptions controller create action:

def create
    @group = Group.find(params[:group_id])
    @subscription = current_user.subscriptions.create(:group_id => @group.id)
    @subscription.save
    respond_to do |format|
      format.html { redirect_to groups_path }
      format.js 
    end
  end

and destroy action:

def destroy
    @group = Group.find(params[:id])
    @subscription = current_user.subscriptions.find_by(group_id: @group.id)
    @subscription.destroy
    respond_to do |format|
      format.html { redirect_to groups_path }
      format.js
    end
   end

& create.js.erb

$("#subscribe_button").html("<%= escape_javascript(render('subscriptions/unsubscribe', locals: { group: @group } )) %>")

& destory.js.erb

$("#unsubscribe_button").html("<%= escape_javascript(render('subscriptions/subscribe', locals: { group: @group } )) %>")

I am still getting the following error in the logs:

Started POST "/subscriptions" for 127.0.0.1 at 2014-11-20 22:23:39 +0000
Processing by SubscriptionsController#create as JS
  Parameters: {"utf8"=>"✓", "group_id"=>"1", "commit"=>"Subscribe"}
  User Load (0.9ms)  SELECT "users".* FROM "users" WHERE "users"."remember_token" = 'b0afd34150d0c021a1e4d0dfa357107a2aa59f00' LIMIT 1
  Group Load (0.4ms)  SELECT "groups".* FROM "groups" WHERE "groups"."id" = $1 LIMIT 1  [["id", "1"]]
   (0.2ms)  BEGIN
  Subscription Exists (0.6ms)  SELECT 1 AS one FROM "subscriptions" WHERE ("subscriptions"."group_id" = 1 AND "subscriptions"."user_id" = 2) LIMIT 1
  SQL (0.6ms)  INSERT INTO "subscriptions" ("created_at", "group_id", "role", "updated_at", "user_id") VALUES ($1, $2, $3, $4, $5) RETURNING "id"  [["created_at", Thu, 20 Nov 2014 22:23:39 UTC +00:00], ["group_id", 1], ["role", "pending"], ["updated_at", Thu, 20 Nov 2014 22:23:39 UTC +00:00], ["user_id", 2]]
   (0.4ms)  COMMIT
   (0.1ms)  BEGIN
  Subscription Exists (0.7ms)  SELECT 1 AS one FROM "subscriptions" WHERE ("subscriptions"."group_id" = 1 AND "subscriptions"."id" != 96 AND "subscriptions"."user_id" = 2) LIMIT 1
   (0.2ms)  COMMIT
  Rendered subscriptions/_unsubscribe.html.erb (100.3ms)
  Rendered subscriptions/create.js.erb (101.7ms)
Completed 500 Internal Server Error in 120ms

ActionView::Template::Error (undefined local variable or method `group' for #<#<Class:0x007fdc05a244a8>:0x007fdc0545b350>):
    1: <%= debug group %>
    2: <div id="unsubscribe_button"> 
    3: <%= button_to "Unsubscribe", subscription_path(group), :remote => true, :method => 'delete', class:  "btn subscribe_btn" %>
    4: </div>
  app/views/subscriptions/_unsubscribe.html.erb:1:in `_app_views_subscriptions__unsubscribe_html_erb__4479900334468069300_70291478478720'
  app/views/subscriptions/create.js.erb:1:in `_app_views_subscriptions_create_js_erb__1667797080065562395_70291478425360'
  app/controllers/subscriptions_controller.rb:8:in `create'

You can clearly see that the @group is set in the create action and is successfully creating a subscription but the local variable is not being set in the js.erb files.

Best Solution

You don't. Execution ends when the current request ends, i.e. when the form is rendered. The .js.erb view template is not called until the form is submitted, starting a new request.

You'll have to create an instance variable e.g. @group = however_you_get_the_group in the controller's create action to make it visible to the .js.erb view, and reference as such: locals: { group: @group }

Related Question