#前提条件
・railsを用いたアプリケーション
・Recipeモデルはhas_many で Likeモデルと紐づいている。
recipe.rb
has_many :passive_likes, class_name: "Like",
foreign_key: "liked_id",
dependent: :destroy
like.rb
class Like < ApplicationRecord
belongs_to :liker, class_name: "User"
belongs_to :liked, class_name: "Recipe"
validates :liker_id, presence: true
validates :liked_id, presence: true
end
#したいこと
・Recipeモデルに紐づくLikeモデルのliked_idの数(count)に順じて降順で表示
される様に並び替えしたい。
#1. Recipeのindexテンプレートのpathにオプションをわたす。
app/views/recipes/index.html.erb
<p><%= link_to "Recent", recipes_path(option: "recent") %></p>
<p><%= link_to "Popular", recipes_path(option: "popular")%></p>
→"Recent"をクリックする=>オプションで"recent"が渡される。
"Popular"をクリックする=>オプションで"pupular"が渡される。
#2.渡されたオプションに即したcontrollersの条件分岐
app/controllers/recipes_controller.rb
def index
if params[:option] == "recent" || params[:option] == nil
@page_title = "Recent Recipes"
@recipes = Recipe.all.order(created_at: :desc).paginate(page: params[:page])
elsif params[:option] == "popular"
@page_title = "Popular Recipes"
# RecipeとLikeテーブル(has_many :passive_likes)を融合する。→Likeテーブルのliked_id(==Recipe.id)でグループカする。(複数あっても1個にまとめる。)→その数をベースに降順に並び替えする。→その中でも新しい物を先にする。→{recipe.id: liked_idの数}のハッシュが帰ってくる。(liked_idの数量を基準にした降順 + その中でも新しいものが先に。)
recipes_hash = Recipe.joins(:passive_likes).group("liked_id").order('count_all DESC').order(created_at: :desc).count
#recipe.hashのキーのみの配列(array)にする。
recipe_ids = recipes_hash.keys
#recipe_idsの順番のままRecipeを配列で返す。
recipe_array = Recipe.find(recipe_ids).sort_by{ |recipe| recipe_ids.index(recipe.id)}
#KaminariGemを活用しrecipe_array(liked_idの数の降順とcreated_atの降順)の順番のまま`@recipes`にrecipeの配列を代入する。
@recipes = Kaminari.paginate_array(recipe_array).page(params[:page]).per(20)
end
end
#3. Kaminariが使える様に Kaminari Gemをインストールする。
→Arrayでページネーションが可能になる。
#4. Recipe.rbに記載していたdefault_scope -> { order(created_at: :desc) }
を削除する。
#5. 必要に応じて各コントローラーの@recipes
にorder(created_at: :desc)
を追加する。