Rails 4: Passing a local variable to a js.erb file from a partial containing a form_for helper
Solution 1
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 }
Solution 2
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 } )) %>")
Related videos on Youtube
rorykoehler
Updated on June 07, 2022Comments
-
rorykoehler almost 2 years
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.
-
rorykoehler over 9 yearsDoes
locals: { group: @group }
make the group local variable available in the partial it is passed to? Your suggestion didn't work for me? -
jemminger over 9 yearsYes. However you must make sure that
@group
exists when you pass it, or you'll get nil forgroup
in your partial. -
rorykoehler over 9 yearsHey I marked your answer as correct as technically it is. I thought I had an answer but came back to this today and I am still running into an issue with the local variables not being passed from the js files. I have updated my question above to include subscription controller code.
-
rorykoehler over 9 yearsHi thanks for your help. This still throws the same error. I have added more code to the question above. The @group variable is being set in the create action but not in the create.js.erb file (or at least it is not being passed as a local variable as desired).
-
jemminger over 9 yearsUsage of the "locals" key in render is unnecessary most of the time, try changing to this:
$("#subscribe_button").html("<%= escape_javascript(render('subscriptions/unsubscribe', group: @group )) %>")
though I'm not sure it will make a difference -
jemminger over 9 yearsYou could also try debugging the state of
local_assigns
in the partial before you attempt to accessgroup
to see what locals are present -
rorykoehler over 9 yearsYou absolute legend. Removing the locals key worked. I knew it would be something simple like that. Can't believe I didn't stumble on it considering all the combination I ended up trying.
-
jemminger over 9 yearsNice! It's probably because the api's gotten convoluted when they made the
partial
key optional inrender
, but only in some cases. It would probably also work by adding thepartial
key:$("#subscribe_button").html("<%= escape_javascript(render(partial: 'subscriptions/unsubscribe', locals: { group: @group } )) %>")
-
Benito Serna over 9 yearsIf you see the new error it says that the
group
variable or method is undefined, and not that is nil. So maybe the problem is in the way you are sending the attributes to the render method. I think that you need to send also thepartial
key, like:render(partial: 'subscriptions/unsubscribe', locals: { group: @group } )
-
rorykoehler over 9 yearsThe problem was to do with the keys in the js code. Look to the above answer... Thanks for your time and help.