Reputation: 14444
I have a Restaurant
model that has_many :dishes, through: dish_categories
. I found a post that shows how to write the view code necessary to get things going for the Acts As Votable gem. My situation differs being that the dish model is the nested resource that's being voted upon.
I tried translating the provided code but to no avail. At this point should I create a new controller for dishes and place the votable actions there? If so how would I setup my route so I can accomplish this on my restaurant's show page?
Models
class Restaurant < ActiveRecord::Base
has_many :dish_categories, dependent: :destroy
has_many :dishes, through: :dish_categories
end
class DishCategory < ActiveRecord::Base
belongs_to :restaurant
has_many :dishes, dependent: :destroy
delegate :name, to: :dish_category, prefix: "category"
delegate :restaurant, to: :dish_category
end
class Dish < ActiveRecord::Base
belongs_to :dish_category
end
Restaurants Controller
...
def upvote
@restaurant = Restaurant.find(params[:id])
@dish = Dish.find(params[:id])
@dish.liked_by current_user
redirect_to @restaurant
end
def downvote
@restaurant = Restaurant.find(params[:id])
@dish = Dish.find(params[:id])
@dish.disliked_by current_user
redirect_to @restaurant
end
...
Routes
resources :restaurants do
member do
put "upvote", to: "restaurants#upvote"
put "downvote", to: "restaurants#downvote"
end
end
Restaurants - Show View
...
<% @restaurant.dishes.each do |dish| %>
<div>
<h2><%= dish.category_name %></h2>
<b><%= dish.name %></b>
<%= link_to "Upvote", like_restaurant_path(dish), method: :put %>
<%= link_to "Downvote", dislike_restaurant_path(dish), method: :put %>
</div>
<% end %>
Upvotes: 1
Views: 336
Reputation: 14444
A number of things needed to be done to get this to work. The first order of business was moving my controller action to my dishes controller. I also added two more actions: unlike
and undislike
for toggle functionailty.
NOTE: Logic for authenticating non-registered for users to liking/disliking dishes would still need to be written but this should help get you started.
Dishes Controller
class DishesController < ApplicationController
before_action :load_restaurant_and_dish, only: [:like, :unlike, :dislike, :undislike]
def like
@dish.liked_by current_user
redirect_to @restaurant
end
def unlike
@dish.unliked_by current_user
redirect_to @restaurant
end
def dislike
@dish.disliked_by current_user
redirect_to @restaurant
end
def undislike
@dish.undisliked_by current_user
redirect_to @restaurant
end
private
def load_restaurant_and_dish
@dish = Dish.find(params[:id])
@restaurant = @dish.restaurant
end
end
Next was configuring my routes to correspond with my restaurant and dish models:
Routes
resources :restaurants do
resources :dishes, only: [:like, :unlike, :dislike, :undislike] do
member do
put "like", to: "dishes#like"
put "unlike", to: "dishes#unlike"
put "dislike", to: "dishes#dislike"
put "undislike", to: "dishes#undislike"
end
end
end
I ended up refactoring my show view and created a few partials to reduce clutter now that there's a little bit of logic involved:
Restaurants - Show View
...
<%= render "restaurants/dish_partials/dishes" %>
...
Dishes Partial
<% @dishes.each do |dish| %>
<div>
<h2><%= dish.category_name %></h2>
<span><b><%= dish.name %></b></span>
<%= render "restaurants/dish_partials/like_toggle", dish: dish %>
</div>
<% end %>
Like Toggle Partial
<% if current_user.liked? dish %>
<%= link_to "Unlike", unlike_restaurant_dish_path(@restaurant, dish), method: :put %>
<% else %>
<%= link_to "Like", like_restaurant_dish_path(@restaurant, dish), method: :put %>
<% end %>
<% if current_user.disliked? dish %>
<%= link_to "Undislike", undislike_restaurant_dish_path(@restaurant, dish), method: :put %>
<% else %>
<%= link_to "Dislike", dislike_restaurant_dish_path(@restaurant, dish), method: :put %>
<% end %>
Upvotes: 2