Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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.

like image 444
rorykoehler Avatar asked Nov 14 '14 20:11

rorykoehler


2 Answers

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 }

like image 89
jemminger Avatar answered Nov 02 '22 23:11

jemminger


The problem is that when you are in the create action, you don't have the variables that you set in the previous action.

So you need to set again the @group instance variable and then use it in your create.js.erb template.

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, flash[:success] = "You have successfully subscribed to this group" }
    format.js
  end
end
$("#new_subscription").html("<%= escape_javascript(render('subscriptions/unsubscribe', locals: { group: @group } )) %>")
like image 30
Benito Serna Avatar answered Nov 02 '22 23:11

Benito Serna