Unlike Button
Let's create an unlike button for users to unlike products. We'll start off in a similar manner as the like button, but then do things a little differently.
route and action
When a user unlikes a product, a like record is destroyed. Can you follow standard Rails practice to create a route and action for unliking a product?
Add :destroy to your likes resources:
resources :likes, only: [:create, :destroy]
Then add a destroy action to the likes_controller:
def destroy
end
Now let's fill in the controller code for destroying a like. This is simpler than creating a like, since we can just take in the id of the like and destroy it, we don't need to deal with any product. Can you fill in the destroy
method so it destroys the like record with the given id?
Simply destroy the like with the given ID. Then redirect the user back to their page:
def destroy
Like.destroy(params[:id])
redirect_to :back
end
setting up
Before we create the unlike button, we need to figure out how to display everything. Both buttons should only be shown to signed in users. The unlike button should only be shown to a user who likes a product, and the like button should only be shown to users who don't like a product. Can you setup these conditions on the product show page?
Use the devise helper method user_signed_in?
to avoid displaying any like buttons to them. Otherwise, display the relevant button:
<div>
<% if ! user_signed_in? %>
<small><%= link_to "Sign in", user_session_path %> to like products.</small>
<% elsif current_user.likes?(@product) %>
<%# todo soon: unlike button form %>
<% else %>
<%= form_tag "/likes" do %>
<%= hidden_field_tag :product_id, @product.id %>
<%= submit_tag "Like", class: "button-primary" %>
<% end %>
<% end %>
</div>
unlike button
Now that everything is setup, let's create the unlike button form. When dealing with an actual model object, Rails provides the form_for
helper to make forms even simpler. First, can you write the ruby code to get the currenty_user's like item for the given @product
?
This code will get the given like:
<% like = current_user.likes.find_by(product_id: @product.id) %>
Now that we have the like, let's use the form_for
helper to create the form:
<%# your previous line of code %>
<%= form_for(like, method: :delete do %>
<%= submit_tag %>
<% end %>
Notice that we specify the method as :delete
so the form submits a delete http request, which will be routed to our delete action. This is all we need for the form to work, but let's again change the text displayed on the button:
<%= submit_tag "Unlike" %>
We should now be able to like and unlike products!
cleanup
To make things neater, let's move the forms to partials. Create a partial _like
for the like button and _unlike
for the unlike button. Render the partials inside your product page.
Create a folder likes inside views and create the partial files _like.html.erb
and _unlike.html.erb
inside them. Cut and paste the buttons from your show product page and into like and unlike, and then render them:
/views/products/show.html.erb
....
<div>
<% if ! user_signed_in? %>
<small><%= link_to "Sign in", user_session_path %> to like products.</small>
<% elsif current_user.likes?(@product) %>
<%= render 'likes/unlike' %>
<% else %>
<%= render 'likes/like' %>
<% end %>
</div>