こんばんは
アロハな男、やすのりです!
今日は、Railsでモデルやテーブルを扱っていく上で1度は必ず通るであろうsort_byメソッド
について書いていこうと思います。
ただ普通に配列を並び替えわけではなく、今回はアソシエーションを組んでいる別テーブルの値
で並び替えをする方法になります!!
#結論
並び替える方法が2種類あります。
全く該当しない物は扱わない
モデル名.joins(:並び替えたい項目があるテーブル名).group(:まとめたい項目).order('count(並び替えたい項目)')
該当しないものも扱いたい
テーブル情報を入れた変数.sort_by { |x| x.並び替えたい項目があるテーブル名 }
となります。
#テーブル構造
例えば以下の様なテーブルがあった場合で考えます。
- experiencesテーブル(色んなお店やレジャー施設情報保存用)
- usersテーブル(登録していただいているユーザー様の情報保存用)
- favoritesテーブル(ユーザー様がお店等をお気に入りしたことを保存)
favoritesテーブルでは、他2つのidを外部キーとして持っています。
ユーザー様がお店やレジャー施設をお気に入り登録すると、
id | user_id | experience_id |
---|---|---|
1 | 1 | 1 |
2 | 1 | 3 |
3 | 2 | 1 |
4 | 3 | 2 |
5 | 2 | 2 |
こんな具合にテーブルに値が保存されていきます。
#なぜ2種類?
それでは、なぜ方法が2種類あるのかを見ていきたいと思います。
まず全く該当しない物は扱わない
場合ですが、
こちらの重要部分はjoinsメソッド
です。
詳しいことは↓こちらを見ていただく方がよりわかりやすいかと思います。
【Rails】joinsメソッドのテーブル結合からネストまでの解説書
簡単に説明すると、例えば
Experience.joins(:favorites)
とすると、experiencesテーブルとfavoritesテーブルの両方共に存在しているレコード情報
しか検索できなくなってしまいます。
つまり、**お気に入り登録をまだされていないお店・レジャー施設は検索対象から外す。**ということになります。
検索対象から外さない場合の物は後述します。
続いて、
Experience.joins(:favorites).group(:experience_id).order('count(user_id) DESC')
と、記述することによりお気に入りされている数が多い順でお店等を取得することができます。
groupメソッド
でexperience_idを指定することにより、複数お気に入り登録されているお店等を1つのレコードにまとめることができます。
そしてorderメソッド
で並び替えをするんですが、メソッド内でcount(user_id)
とすることによってお店等がお気に入り登録されている数で並び替えることができます。
ただこの方法ですと、お気に入り登録されている場所だけをピックアップして、そこから人気店を探す!!とかなら使用できるメソッドですが、**お店等を全て一覧で表示したいから除外されてしまうのは...**という場合もあると思います。
『それならjoinsメソッド
を抜いてコードを書けばいいじゃん!!』
となりそうなんですが、その後のgroupメソッド
ではexperience_idを、countメソッド
ではuser_idを使用しています。
この2つのidはfavoritesテーブル
が持っているテーブルですので、Experienceモデルだけでは使用できません...
その場合には、もう1種類の方法です。
#全て取得する方法
該当しないものも扱いたい
場合ですが、こちらは先ほどまで説明していた方法とは少し違います。
具体的にはモデルではなくテーブルに対して並び替えをする
ということです。
1度変数等にレコード情報を格納してしまいます(今回は@experiences
とします。)
そして変数に対してsort_byメソッド
を使用します。
@experiences.sort_by! { |exp| exp.favorites.length }.reverse!
と記述することで、全件のお店等を対象にお気に入り数が多い順で並び替えることができます。
sort_byメソッド
を使用することで変数(配列)の並び替えをでき、{}
内でその値を1つずつ取り出して評価していきます。
experiencesテーブル
とfavoritesテーブル
はアソシエーションを組んでますので、
exp.favorites.length
と記述することで、1つずつ取り出してきたお店のお気に入り数を評価して並び替えをしてくれます。
ただこのままだと昇順での並び替えになってしまいますので、最後にreverseメソッド
で結果を反転させています。
#最後に
最初は全部モデルに対してだけで並び替えができると思い込んでいたので、すごく時間がかかってしまいました...
いや、もしかしたらこれ以外にもっといい方法があるかも...?
ご指摘・アドバイスはどんどんいただきたいと思っていますので、コメントお待ちしています!!