mergeはmergeでもHashじゃなくてActiveRecord::SpawnMethodsのmergeなのです。
join先のテーブルの条件で絞り込みたい
class Entry < ActiveRecord::Base has_many :comments end
class Comment < ActiveRecord::Base belongs_to :entry end
例えばブログのエントリーの公開・非公開がいつでも切り替えられるとして、非公開になっているブログのコメントを抽出したいな、と思ったとします。
公開・非公開かはentriesテーブルのpublished_atカラムにDateTimeがセットされているかされていないかで分かるとすると、以下のようなコードになると思います。
Comment.joins(:entry).where(entries: { published_at: nil })
でも、entries: { published_at: nil }
の部分って、もう少し表現を変えられないかな?って思いますよねー! このコードの意味するところは「この記事は公開されていない、いわば下書きの状態である」と言いたいので、その通りにコードを書きたいですよね。
抽出条件に名前をつけるにはActiveRecordのNamed Scopeという機能を使います。つまりこういうことですね。
class Entry < ActiveRecord::Base has_many :comments scope :draft, -> { where(published_at: nil) } end
このscopeで定義した条件を利用するのに、ActiveRecord::SpawnMethods#mergeを使うことができます。mergeを使うとこんなコードになります。
Comment.joins(:entry).where(Entry.merge(:draft))
scopeを利用しない場合はこんな風に書くこともできます。
Comment.joins(:entry).merge(Entry.where(published_at: nil))
空気読んで勝手にINNER JOINしてくれれば良いのですが、そうはいかないのでjoins
は必要です。
・・・と、こんな小ネタをまとめたActiveRecord大全なんかあれば良いのにな、と思う今日この頃でした。