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

11,983

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 } )) %>")
Share:
11,983

Related videos on Youtube

rorykoehler
Author by

rorykoehler

Updated on June 07, 2022

Comments

  • rorykoehler
    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
    rorykoehler over 9 years
    Does locals: { group: @group } make the group local variable available in the partial it is passed to? Your suggestion didn't work for me?
  • jemminger
    jemminger over 9 years
    Yes. However you must make sure that @group exists when you pass it, or you'll get nil for group in your partial.
  • rorykoehler
    rorykoehler over 9 years
    Hey 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
    rorykoehler over 9 years
    Hi 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
    jemminger over 9 years
    Usage 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
    jemminger over 9 years
    You could also try debugging the state of local_assigns in the partial before you attempt to access group to see what locals are present
  • rorykoehler
    rorykoehler over 9 years
    You 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
    jemminger over 9 years
    Nice! It's probably because the api's gotten convoluted when they made the partial key optional in render, but only in some cases. It would probably also work by adding the partial key: $("#subscribe_button").html("<%= escape_javascript(render(partial: 'subscriptions/unsubscribe', locals: { group: @group } )) %>")
  • Benito Serna
    Benito Serna over 9 years
    If 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 the partial key, like: render(partial: 'subscriptions/unsubscribe', locals: { group: @group } )
  • rorykoehler
    rorykoehler over 9 years
    The problem was to do with the keys in the js code. Look to the above answer... Thanks for your time and help.