LoginSignup
30
27

More than 5 years have passed since last update.

ランキング機能実装

Last updated at Posted at 2018-02-16

ランキング機能

私の勝手な見解ですが、ランキング機能は、人々の目をサービスに惹かせるにはとてもいい機能だと思います。
自分の投稿したものが今何位なのかというのは、商品を作成する側からすると非常に気になるものです。
今ではありふれている機能ですが、しっかり戦略があるんだろうなあ。。という薄っぺらい意見から、機能実装入りますw
今回は、特定の食べ物(=food)が、いいねの数によってランキングされるという機能です。

ランキング機能実装

MVCから入ります。

model

food.rb

has_many: likes

#like.rb
belongs_to: food

view

index.html.erb
#ランキング結果を全て出したい時
<%=@food_ranking.all%>

#1位だけを出したい時
<%=@food_ranking.first%>

ここちょっと悩みどころなんですけど、開発途中だとランキング1位がnilの場合が多いから、強制的にエラーになります。
すでにランキングが埋められている状態で開発するか、nilの場合とそうでない場合をif文で切り分けるか好きなようにすれば良いかと。。
ちなみに自分は、if文で切り分けています。正式にリリースとかするのであれば切り分けた方がいいかもです。。。
この例では入れてないですが。。

controller

いよいよネックのコントローラーです

foods_controller.rb
 food_like_count = Food.joins(:likes).group(:food_id).count
 food_liked_ids = Hash[food_like_count.sort_by{ |_, v| -v }].keys
 @food_ranking= Food.where(id: food_liked_ids)

正直ここは初心者からしたら、かなりの難題でした。。。。

一個一個見ていきます

1行目 food_like_count = Food.joins(:likes).group(:food_id).count

・joins

内部結合を行うメソッドです。内部結合って何やねんって話なんですが、図を見るとわかりやすいです。

スクリーンショット 2018-02-16 15.13.39.gif

今、foodテーブルとlikeテーブルの状態が上記のようになっているとします。
右のlikeテーブルは、ある特定のユーザーが、特定のfoodをいいねしている状態を表しています。すなわちいいね機能です。一番上のレコードは3というuserが1であるvegetableをいいねしていることになります。
※わかりづらいという方は、ここについて詳しく書いている記事がありますので、お読みください。=>いいね機能の実装と仕組みhttps://qiita.com/tomoharutsutsumi/items/4b045fa12f29502f4b4b

ではこれを内部結合すると。。。
スクリーンショット 2018-02-16 15.17.14.gif
このようになります。ちょっと特徴的なのはlikeテーブルで存在していないfood_id(この場合は3のfishです)は削除されています。

・group

これは読んで字のごとく、グループ化します。さらに詳しくいうと特定のカラムを基準としグループ化します。
今回は.group(:food_id)となっています。
上の内部結合の例で言えば、food_idが同じものをまとめるという動作になります。food_idが1であるものが2つあるので、これらはまとめられます。

・count

これは有名な数えるメソッドです。上のgroupでまとめたものの中身が何個あるかを数えます。
上の表であれば、food_id1は2、2は1になります。

ちなみにこの1行目を動作させると、答えはハッシュになります。
※ハッシュとはなんぞやの記事=>ハッシュと配列の違いhttps://qiita.com/tomoharutsutsumi/items/2dd5dd4b6edb17244cd6
{1=>2, 2=>1}という感じで返ってきます。

2行目 food_liked_ids = Hash[food_like_count.sort_by{ |_, v| -v }].keys

・Hash

ざっくりいうと、これは配列になっているものをハッシュに変換できるものです。

・sort_by{ |_, v| -v }

まずはsort_byですが{}内にある条件で、要素の順番を並べ替えなさいというメソッドです。今回でいう要素とはfood_rankの中にある値のことです。(ex.{1=>2, 2=>1})
では条件とは何かなんですが。。。これは「value(1=>2で言えば2の部分)が大きい順で」という意味です。
そうすれば、いいねをしている人数が増えることになるので、結果ランキング上位の並び替えとなります。

・keys

最後にこの部分ですが、これはハッシュのキーの部分(1=>2で言えば1の部分)を取り出します。
これで、いいねしているユーザーが多い順にfoodのidが取れます。

3行目 Food.where(id: food_liked_ids)

ランキングにされたidと同じidを持っているfoodを見つけます。

これで、ランキングの完成です。

補足

ちなみに以下の記事と合わせて読んでいただければ、ユーザーがいいねできるようになり、かつそのいいね数によってランキングができるようになる、というそれっぽいことが実現できます。ぜひ!
いいね機能の実装と仕組みhttps://qiita.com/tomoharutsutsumi/items/4b045fa12f29502f4b4b

30
27
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
30
27