👩‍❤️‍👨

【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問題は起こらなくなります。詳細は下記リンクに記載してあります。

https://pikawaka.com/rails/includes

  • sort_by{ |x| -x~.count
    sort_byメソッドを使って、並び替えをおこないます。
    |x|xは共通名にして任意に名前をつけます。デフォルトは昇順に並び替えるので-xのようにマイナス記号を付けることによって降順に変更することができます。countをつけることによって、数の並び替えを指示しています。詳細は下記のリンクをご覧ください。

https://zenn.dev/ganmo3/articles/fdda007796a7cb

  • favorites.where(created_at: from...to)
    いいね情報の中で、日時が一週間以内のものをwhereメソッドで検索しています。

以上、いいねの並び替え機能の紹介でした!
今回は紹介しませんでしたが、sortメソッドを使った方法もあるみたいです!
気になる方はぜひ調べて実装してみてください!

あと、モデルの記述・・・分かる方いらっしゃいましたら是非コメントをお待ちしています!

参考にした記事

https://zenn.dev/ganmo3/articles/cfd129246f47c4
https://qiita.com/ooyama-tetu/items/1e19fea32908a6a737f5

Discussion