group/key/count
class RankingController < ApplicationController layout 'review_site' before_action :ranking def ranking product_ids = Review.group(:product_id).order('count_product_id DESC').limit(5).count(:product_id).keys @ranking = product_ids.map { |id| Product.find(id) } end end
Review.group(:product_id) #=> product_idカラムの値が同じレコードのまとまりを作る
まずはgroupメソッドでひとつのカラムの値ごとにレコードをまとめます。
Review.group(:product_id).order('count_product_id DESC').limit(5) #=> まとまりの数が多い順に並び替え、上位5件を取得
order('count_カラム名').count(カラム名)
countメソッドの引数にカラム名を指定することができます。するとorderメソッドでcount_カラム名でのソートが可能となります。これはそのカラムを持つレコードの数でソートするという意味です。
つまり上の例では、product_idでまとめたレコードをレコード数でソートして、カラム名とレコード数のハッシュで返す、という処理になっています。
order('count_product_id DESC')によってまとまりの数が多い順にソートし、limitメソッドで上位5つのまとまりのみ取得します。
Review.group(:product_id).order('count_product_id DESC').limit(5).count(:product_id) #=> この段階の返り値はハッシュになる
さらに、countメソッドにより、まとまりのproduct_idカラムの値をキー、同カラムの同じ値のレコードの数をバリューとするセットが5つ入ったハッシュを生成します
Review.group(:product_id).order('count_product_id DESC').limit(5).count(:product_id).keys #=> この段階の返り値は配列になる
最後に、ハッシュのキーのみの配列を返してくれるkeysメソッドを使用し、最終的にレビューの数が多いproduct上位5件のidが順番に並んだ配列を取得しています。
これで、product_idsはレビューの数が多いproduct上位5件のidが順番に並んだ配列であることがわかりました。続いて、6行目です。
mapメソッドは、端的に言うと配列の中身一つ一つに対して一定の処理を行い、配列の元の場所に戻したものを返り値とするメソッドです。
今回は、Product.find(id)の部分が特定の処理にあたります。idにはproduct_idsの中身一つ一つ、つまりproductsテーブルのレコードのidが入ります。つまりこの処理は、ただのid番号だったものをproductsテーブルのレコードのインスタンスに変換するというものです。結果、左辺である@rankingにはレビューの数が多いproductsテーブルのレコード上位5件が順番に並んだ配列が代入されます。