今回は、本の投稿一覧ページで、過去一週間でいいねの合計カウントが多い順に投稿を表示して行きます!
初めに
本投稿アプリ作成中!
前提条件
・device導入 ・Bootstrap導入
・ユーザー機能実装済(Userモデル)
・投稿機能実装済(Bookモデル)
・いいね機能実装済 (favoriteモデル)
アソシエーション追加
has_many :favorited_users, through: :favorites, source: :user を追記します。
この関連付けは、多対多の関係を持つモデル間の関連付けを簡潔に表現するためのコードであり、中間テーブルを介して関連するモデルにアクセスすることができるようにします。
through: :favorites, source: :user
(投稿モデルが直接ユーザーモデルにアクセスすることができるようにする。)
through: :favorites
(中間テーブルを指定しています。中間テーブルは、投稿とユーザーの関連付けを繋ぐ役割を果たす)
この関連付けを使うことで、投稿モデルからfavorited_usersというメソッドを呼び出すことができます。これにより、投稿にお気に入りをしたユーザーのリストを取得することができます。
book_rb
に以下のように追加
class Book < ApplicationRecord
belongs_to :user
has_many :book_comments, dependent: :destroy
has_many :favorites, dependent: :destroy
+ has_many :favorited_users, through: :favorites, source: :user
validates :title,presence:true
validates :body,presence:true,length:{maximum:200}
def favorited_by?(user)
favorites.exists?(user_id: user.id)
end
favorite.rb (今回は特に追加なし)
class Favorite < ApplicationRecord
belongs_to :user
belongs_to :book
end
user.rb
になければ以下のように追加する。
has_many :books
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
+ has_many :books, dependent: :destroy
has_many :book_images, dependent: :destroy
has_many :book_comments, dependent: :destroy
has_one_attached :profile_image
+ has_many :favorites, dependent: :destroy
コントローラ
def index
to = Time.current.at_end_of_day
from = (to - 6.day).at_beginning_of_day
@books = Book.includes(:favorited_users).
sort {|a,b|
b.favorited_users.includes(:favorites).where(created_at: from...to).size <=>
a.favorited_users.includes(:favorites).where(created_at: from...to).size
}
@book = Book.new
@user = current_user
to 変数は現在の日時の終わりを表し、from 変数はそれから6日前の日時の始まりを表しています。
to = Time.current.at_end_of_day
from = (to - 6.day).at_beginning_of_day
Bookモデルのデータを取得し、それに関連するfavorited_users(いいねをしたユーザー)のデータも同時に取得しています。
その後、sortメソッドを使用してデータの並び替えを行っています。
ブロック内のコード |a,b| は、2つのBookオブジェクトを比較して、どちらのオブジェクトがより多くのいいねを持っているかを判断しています。
@books = Book.includes(:favorited_users).
sort {|a,b|
b.favorited_users.includes(:favorites).where(created_at: from...to).size は、
オブジェクトbに関連するfavorited_users(いいねをしたユーザー)の中で、指定された期間(fromからto)に作成されたいいねの数を取得しています。
具体的には、includes(:favorited_users) がプリロードの処理を行っています。
同様に、a.favorited_users.includes(:favorites).where(created_at: from...to).size は、
オブジェクトaに関連するfavorited_usersの中で、指定された期間に作成されたいいねの数を取得しています。
そして、これらのいいねの数を比較して、並び替えの基準となる値を返しています。<=>演算子は比較演算子であり、左辺と右辺を比較し、結果に基づいてソートの順序を決定します。
b.favorited_users.includes(:favorites).where(created_at: from...to).size <=>
a.favorited_users.includes(:favorites).where(created_at: from...to).size
リファレンスマニュアル
https://docs.ruby-lang.org/ja/latest/method/Array/i/sort.html
プリロードとは
関連するデータを効率的に取得するための手法です。
プリロードを使用すると、事前に関連するデータをまとめて取得することができます。これにより、データベースへのアクセス回数を減らし、処理速度を向上させることができます。上記のコードでは、 Book.includes(:favorited_users) という部分がプリロードの例です。これにより、Bookオブジェクトと関連するfavorited_users(いいねをしたユーザー)のデータを一括で取得しています。