👩❤️👨
【Rails】いいねを多い順に並び替えする方法
概要
投稿された本の一覧画面に並ぶいいね(♥)があります。
更新をかけると過去一週間でいいねの合計を参考にし、降順(数の多い順)に並び替えられるという機能を実装したいと思います。
完成図
更新前
更新後
ER図
Bookモデルへの記述
book.rb
has_many :favorites, dependent: :destroy
has_many :week_favorites, -> { where(created_at: where(created_at: 1.week.ago.beginning_of_day..Time.current.end_of_day)) }, class_name: 'Favorite'
, class_name: 'Favorite'
-
week_favorites
任意のアソシエーションを定義します。
一行上の中間テーブルのアソシエーションの後に記述をします。 -
-> { where(...)}
has_many
に対してwhereメソッドを用いる時の記述です。
Railsガイド - 4.3.3 has_manyのスコープ - 'created_at: ~'
いいねした日時に関わるfavoritesテーブルデフォルトのカラムです。
ここ以降は指定したい期間の記述を行っていきます。 -
1.week.ago.beginning_of_day
なんとなく、英語の雰囲気で分かる通り「一週間前の日の始まり」です。
本日が10/8であるとしたら、一週間前の日付が10/1、始まりの時刻の0時0分0秒を取得しています。 -
Time.current.end_of_day
「現在の終了日時」を指定しています。
上の例にとると、現在の日付10/8、時刻が23時59分59秒を取得しています。 -
class_name: 'Favorite'
アソシエーション名を任意で設定しているので、元はどのモデルであるかを明示しています。
【Rails】class_nameとsourceオプションで分かりやすいアソシエーション名をつけよう
日時取得関係の部分は回りくどくなってしまいましたが、
要約すると「一週間」のデータを取得するためのクエリです。
booksコントローラーへの記述
books_controller.rb
def index
@book = Book.new
# @books = Book.all
to = Time.current.at_end_of_day
from = (to - 6.day).at_beginning_of_day
@books = Book.includes(:favorites).
sort_by{ |x|
-x.favorites.where(created_at: from...to).count
}
end
-
to = Time.current.at_end_of_day
モデルの部分でも触れましたが、「現在の終了日時」をto
へ代入しています。 -
from = (to - 6.day).at_beginning_of_day
(to - 6.day)
で一週間前の日時を取得します。
例えば今日が10/8(日)なら10/2(月)を取得します。
ただし、このままでは10/8(日)23時59分59秒の丸6日前、つまり10/2(月)23時59分59秒となってしまうので.at_beginning_of_day
で10/2(月)0時0分0秒に設定します。
-
Book.includes(:favorites)
Bookモデルに関連するいいね情報を全て取得します。
includeメソッドとN+1問題について
@books = Book.all.sort_by{ |x|
-x.favorites.where(created_at: from...to).count
}
今回はallメソッドを使っても機能の実装は可能です。
しかし、このような書き方をするとSQLの出力の回数が増えてしまい動作が悪くなってしまいます。これをN+1問題といいます。includeメソッドを使用することによって、その負担は軽くなり、N+1問題は起こらなくなります。詳細は下記リンクに記載してあります。
-
sort_by{ |x| -x~.count
sort_byメソッドを使って、並び替えをおこないます。
|x|
とx
は共通名にして任意に名前をつけます。デフォルトは昇順に並び替えるので-x
のようにマイナス記号を付けることによって降順に変更することができます。count
をつけることによって、数の並び替えを指示しています。詳細は下記のリンクをご覧ください。
-
favorites.where(created_at: from...to)
いいね情報の中で、日時が一週間以内のものをwhereメソッドで検索しています。
以上、いいねの並び替え機能の紹介でした!
今回は紹介しませんでしたが、sortメソッドを使った方法もあるみたいです!
気になる方はぜひ調べて実装してみてください!
あと、モデルの記述・・・分かる方いらっしゃいましたら是非コメントをお待ちしています!
参考にした記事
Discussion