OKADA LABO

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件が順番に並んだ配列が代入されます。