Zzz
Zzz

Reputation: 439

AJAX Form is submitting correctly but failing to refresh form

I'm trying to add twitter-esque feeds into my application by modifying the guide from Michael Hartl's book: https://www.railstutorial.org/book/following_users

There is a "follow" button that should turn into "unfollow" or vice versa when pressed. The form is submitting successfully (If I refresh the page, it changes the button to the correct version, and the relationships are being created in the database), but the button simply fails to change to the correct version without a full page refresh.

_follow_form.html.erb (partial loaded by main view page)

<div id="follow_form">
  <% if current_user.following?(@restaurant) %>
    <%= render 'restaurants/unfollow' %>
  <% else %>
    <%= render 'restaurants/follow' %>
  <% end %>
</div>

_follow.html.erb (follow button)

<%= bootstrap_form_for(current_user.active_relationships.build, remote: true) do |f| %>
  <div><%= hidden_field_tag :followed_id, @restaurant.id %></div>
  <%= f.submit "Follow", class: "btn btn-primary" %>
<% end %>

_unfollow.html.erb (unfollow button)

<%= bootstrap_form_for(current_user.active_relationships.find_by(followed_id: @restaurant.id),
             html: { method: :delete }, remote: true) do |f| %>
  <%= f.submit "Unfollow", class: "btn" %>
<% end %>

Relevant controller

class RelationshipsController < ApplicationController
  before_action :authenticate_user!

  def create
    restaurant = Restaurant.find(params[:followed_id])
    current_user.follow(restaurant)
    respond_to do |format|
      format.html { redirect_to @restaurant }
      format.js
    end    
  end
  def destroy
    restaurant = Relationship.find(params[:id]).followed
    current_user.unfollow(restaurant)
    respond_to do |format|
      format.html { redirect_to @restaurant }
      format.js
    end
  end
end

create.js.erb

$("#follow_form").html("<%= escape_javascript(render('restaurants/unfollow')) %>");
$("#followers").html('<%= @restaurant.followers.count %>');

destroy.js.erb

$("#follow_form").html("<%= escape_javascript(render('restaurants/follow')) %>");
$("#followers").html('<%= @restaurant.followers.count %>');

Here is the error I am getting according to Chrome:

NoMethodError in Relationships#destroy

Showing /home/ubuntu/workspace/suburblia/app/views/restaurants/_follow.html.erb where line #2 raised:
undefined method `id' for nil:NilClass
Trace of template inclusion: app/views/relationships/destroy.js.erb
Rails.root: /home/ubuntu/workspace/suburblia

Upvotes: 1

Views: 62

Answers (2)

Gerry
Gerry

Reputation: 10507

That's because @restaurant is a class instance variable and as such it is available in your views, but restaurant is a local variable, only available within the method (i.e. action) it is defined.

Your view calls for that variable in <%= @restaurant.followers.count %> but since you were defining a local variable restaurant, it wasn't available to your view and you got a undefined method 'id' for nil:NilClass error; that is @restaurant returned nil instead of a Restaurant object.

But when you changed it to @restaurant you made it available to your view, so no more nil values.

Upvotes: 1

Zzz
Zzz

Reputation: 439

I needed to change restaurant in the controller to @restaurant. Not sure why, but this worked. Any explanations would be cool!

Upvotes: 1

Related Questions