Alex Heil
Alex Heil

Reputation: 345

Follow/Unfollow with Ajax on Rails 4

I've been trying to implement Ajax for a while now and am unsuccessful in fully completing the process.

I can get it to post to the database no problem, but am having trouble with the JavaScript side of everything, more specifically showing the unfollow button to someone who has followed and the follow button to someone who has just unfollowed.

Veiw - artists/show.html.erb

<% if fan_signed_in? && current_fan.following_artist?(@artist) %>
  <%= button_to "unfollow", artist_relationship_path, method: :delete, remote: true, class: "exchange" %>
<% else %>
  <%= form_for(ArtistRelationship.new,  url: artist_relationships_path, remote: true) do |f| %>
    <%= hidden_field_tag :artist_id, @artist.id %>
    <%= f.submit "follow", class: "exchange" %>
  <% end %>
<% end %>

Controller - artists/relationships_controller.rb

before_action :authenticate_fan!
respond_to :html, :js

def create
  @relationship = ArtistRelationship.new
  @relationship.fan_id = current_fan.id
  @relationship.artist_id = Artist.friendly.find(params[:artist_id]).id
  if @relationship.save
    redirect_to (:back)
  else
    redirect_to root_url
  end
end

def destroy
  current_fan.unfollow_artist(Artist.friendly.find(params[:id]))
  redirect_to (:back)
end

View - artists/relationships.js.erb

// I am lost here. I have no idea at all what goes in this file.

I also do not know if my controller is handling the request correctly. I just took that from a tutorial I've been following.

Any help would... help =]

edit in response to beartech's answer I can click follow and it will successfully post to the database, however the view does not update. Upon refreshing the page, the follow button does show as unfollow and vice versa.

My logs say ActionView::MissingTemplate (Missing template artists/relationships/create) which makes sense as there is no create view for relationships as it's done on the artists/show.html.erb.

I'm almost positive something in the controller is not working properly with responding to the JavaScript.

Upvotes: 2

Views: 732

Answers (1)

Beartech
Beartech

Reputation: 6411

Your JS file just needs to contain the code to change the button link from one state to the other. Since you have the if/then statement to determine which to show, you could put it in a div and have the JS update that div.

First you need to be able to respond to JS in your controller:

artists/relationships_controller.rb:

def create
  @relationship = ArtistRelationship.new
  @relationship.fan_id = current_fan.id
  @relationship.artist_id = Artist.friendly.find(params[:artist_id]).id
  if @relationship.save
      respond_to do |format|
      format.html { redirect_to(:back) }
      format.js {render :action => "follow_button" }
    end
  else
    redirect_to root_url
  end
end

def destroy
  current_fan.unfollow_artist(Artist.friendly.find(params[:id]))
  respond_to do |format|
    format.html { redirect_to(:back) }
    format.js {render :action => "follow_button" }
  end
end

Wrap your button code in a div:

artists/show.html.erb:

<div class='follow_button'>
<% if fan_signed_in? && current_fan.following_artist?(@artist) %>
  <%= button_to "unfollow", artist_relationship_path, method: :delete, remote: true, class: "exchange" %>
<% else %>
  <%= form_for(ArtistRelationship.new,  url: artist_relationships_path, remote: true) do |f| %>
    <%= hidden_field_tag :artist_id, @artist.id %>
    <%= f.submit "follow", class: "exchange" %>
  <% end %>
<% end %>
</div.

Now in your JS file:

artists/follow_button.js.erb:

$('#follow_button').html('<%= escape_javascript(render :partial => 'follow_button') %>');

And the partial code:

artists/_follow_button.html.erb:

<% if fan_signed_in? && current_fan.following_artist?(@artist) %>
  <%= button_to "unfollow", artist_relationship_path, method: :delete, remote: true, class: "exchange" %>
<% else %>
  <%= form_for(ArtistRelationship.new,  url: artist_relationships_path, remote: true) do |f| %>
    <%= hidden_field_tag :artist_id, @artist.id %>
    <%= f.submit "follow", class: "exchange" %>
  <% end %>
<% end %>

You will probably need to adjust paths to suit your needs.

The lifecycle of AJAX is:

:remote call to controller -> respond to JS -> JS file gets executed.

Upvotes: 1

Related Questions