たとえば、複数のバージョンを持つブログの記事を下記のようなモデルで表現しているとする。
class Entry < ApplicationRecord
has_many :versions
def latest_version
versions.order(number: :desc).first
end
end
class Version < ApplicationRecord
belongs_to :entry
# 新しいバージョンほど number の値が大きいものとする
validates :number, uniqueness: true, numericality: {greater_than: 0, only_integer: true}
end
このとき最新のバージョンは Entry.find(1).latest_version
で得られるが、単なるメソッドなので includes
などを使うことができない。
has_one
では絞り込みの条件を lambda で渡す事ができるので下記のように書けばよい。
class Entry < ApplicationRecord
has_many :versions
has_one :latest_version, -> {
# 同じ entry_id で number がこれより大きいレコードが存在しない、という条件
where(
<<~SQL
NOT EXISTS (
SELECT 1 FROM versions AS v
WHERE
versions.number < v.number AND
versions.entry_id = v.entry_id
)
SQL
)
}, class_name: "Version"
end
これで Entry.includes(:latest_version).find(1).latest_version
のように書ける。