🐣

過去1週間のいいねの数が多い順に投稿を表示する

2023/07/05に公開

[Ruby on Rails] で過去1週間のいいねの数が多い順に投稿を表示する

アソシエーション

user.rb
has_many :books, dependent: :destroy
has_many :favorites, dependent: :destroy!
book.rb
  belongs_to :user
  has_many :favorites, dependent: :destroy
  has_many :favorited_users, through: :favorites, source: :user
解説

多対多のアソシエーションの場合
has_many: \textcolor{red}{中間テーブル}
has_many: \textcolor{blue}{関連先のテーブル名} through \textcolor{red}{中間テーブル}
を指定します。

  • through
    「経由する」という意味で、中間テーブルを経由して、関連先のオブジェクトを取得することができます。

  • source
    多対多の関連先のモデル名を指定するオプション

なので今回は favoritesテーブルを経由して Userモデルのオブジェクトを取得するという意味になります。

favorite.rb
  belongs_to :user
  belongs_to :book

コントローラー

books_controller.rb
  def index
    to = Time.current.at_end_of_day
    from = (to - 6.day).at_beginning_of_day
    @books = Book.includes(:favorited_users).sort_by {|x|
     x.favorited_users.includes(:favorites).where(created_at:
     from...to).size}.reverse
    @book = Book.new
  end
解説

to = Time.current.at_end_of_day

  • Time.current は TimeWithZone クラスを使用している
  • Time.current で config/application に指定してある日時を取得している
  • at_end_of_day でその日の終わりを指定している

from = (to - 6.day).at_beginning_of_day

  • 一週間という意味

@books = Book.includes(:favorites)

  • 前まではBook.all を使用していた
  • includes とは関連付けられているモデルを取得するメソッドで、無駄なSQL文を出したくない時に使用する
  • includes の後ろの ()でモデルを指定する

sort_by {|x| x.favorited_users.includes(:favorites).where(created_at: from...to).size}.reverse

  • sort_by で配列の中から昇順に取り出し、reverseで降順で表示させる
  • where メソッドは()の中の条件に合うレコードを取得したりするメソッド

こちらの記事を参考にさせていただきました。

Discussion