Harry B.
Harry B.

Reputation: 421

Like button likes all posts

I've implemented a like/unlike function in my app. On the show page for an item, you can like/unlike without any issues. On a user's profile page though, where it lists all the foods they've uploaded, I have two issues: First, when I click the like button for one food, it triggers it for every food and then the button text under every food says "unlike this food", instead of only having the button text change for just the food that was clicked on. The like gets saved to the db for the correct food, but obviously I don't want the button text to change for foods that I haven't liked. Second, when I try to like a different food on the page without refreshing, the liked gets saved in the db as the original food that I clicked on, instead of the one I actually clicked on.

users.show.html.erb

<% @user.foods.each do |food| %>
    <div class="row col-md-12">
        <div class="food col-md-4">
            <h3 class="title"><%= link_to food.title.capitalize, food_path(food.id) %></h3>
            <%= link_to (image_tag (food.image.url)), food_path(food.id) %>
            <%= render 'shared/vote_form', :food => food %>

            <%= link_to pluralize(food.votes.count, "person"), user_votes_path(:user_id => current_user.id, :food_id => food.id) %> <%= food.votes.count == 1 ? 'wants' : 'want' %> to gobble this
        </div>

        <div class="description col-md-6">
        <% if @user.id == current_user.id %>

                <% if food.description.length == 0 %>
                    <p><%= link_to "Add Description", edit_food_path(food) %></p>   
                <% else %>
                    <p><%= food.description %><p>
            <p><%= link_to "Edit Description", edit_food_path(food) %></p>
                <% end %>

          <% if food.recipe.length == 0 %>
            <p><%= link_to "Add Recipe", edit_food_path(food) %></p>
          <% end %>

        <% else %>

          <% if food.description.length == 0 %>
            <p>No Description</p> 
          <% else %>
            <p><%= food.description %><p>
          <% end %>

          <% if food.recipe.length == 0 %>
            <p>No Recipe</p>
          <% else %>
            <p><%= link_to "View Recipe", food_path(food) %></p>  
          <% end %>

        <% end %>
        </div>
    </div>
<% end %>

votes controller

class VotesController < ApplicationController

  def index
    @votes = Food.find(params[:food_id]).votes
  end

  def new
    @vote = current_user.votes.new
  end

  def create
    @user = current_user
    @vote = current_user.votes.build(vote_params)


    if @vote.save!
      @food = @vote.food
      respond_to do |format|
        format.html {redirect_to :back, notice: "Liked!"}
        format.js  
      end

      puts @vote.food.id
    else
      puts "No"
      redirect_back(fallback_location: root_path)
    end
  end

  def show
    @user = current_user
    @vote = Vote.find(params[:id])
  end

  def destroy
    @vote = Vote.find(params[:id])
    @food = @vote.food

    if @vote.destroy!
      respond_to do |format|
        format.html {redirect_to :back, notice: "Unliked!"}
        format.js 
      end
    else
      puts "NOOOOOO"
    end
  end

  private

  def vote_params
    params.require(:vote).permit(:food_id)
  end
end

vote partial

<% unless current_user.votes.pluck(:food_id).include?(food.id) %>
    <%= button_to "Like This Food", user_votes_path(current_user, { vote: { food_id: food.id } }), :remote => true %>
<% else %>
    <% vote = food.votes.where(user_id: current_user.id).first %>
    <%= button_to "Unlike This Food", user_vote_path(current_user, vote), :remote => true, method: "delete" %>
<% end %>

create.js.erb

$('.button_to').replaceWith("<%= j (render :partial => 'shared/vote_form', :locals => { :food => @food, :food_id => @food.id }) %>");

destroy.js.erb

$('.button_to').replaceWith("<%= j (render :partial => 'shared/vote_form', :locals => { :food => @food }) %>");

Upvotes: 0

Views: 106

Answers (1)

Greg Navis
Greg Navis

Reputation: 2934

Take a look at your create.js.erb (destroy.js.erb has the same problem). You use select all elements with the class button_to - that is all buttons on the page. Then you call replaceWith that replaces all these buttons with the button provided as the argument. The result is that all buttons get replaced with the like button corresponding to the food you just liked. This is responsible for affecting all buttons on the page and making them refer the food you liked first.

The solution is to add an id attribute to the buttons that would include the ID of the food the button pertains to. For example, if Food with ID 1 is Lettuce then you need to add id="like-1" to the button and change $('.button_to') to $("#like-1").

Upvotes: 1

Related Questions