Edited at

ActiveRecord で "最新の子" を has_one で表現する

たとえば、複数のバージョンを持つブログの記事を下記のようなモデルで表現しているとする。

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 のように書ける。