scope の罠
先日以下のような scope を見ました。
class User < ActiveRecord::Base
scope :foo, -> (bar) do
return if bar.nil?
find_by(bar: bar)
end
end
もちろん使い方しだいではありますが、この動き、ちょっと想定外だったりするので注意です。
bar
が nil
で return
される場合 (nil
が返る)、
find_by
で見つからなくて nil
になる場合、
このとき、scope の戻りは nil
ではありません。
User.foo(nil)
は nil ではありません。
User.all
が返ります。
(正確には default scope が返る)
なぜ nil
が返らないのか
どうやら scope
は ActiveRecord::Relation
を返すものだと決まっているよう。
なのでnil
が返るときは default scope である User.all
を返すようです。
以下の記事が理解しやすかったです。
User.foo.where(baz: baz)
のようにチェインすることを考えると、たしかに nil
で返ると困りますね。
じゃぁ find_by すべきではないんじゃ?
find_by
して得られるのはそのモデルクラスのインスタンス(またはnil
)なので、「scope
は ActiveRecord::Relation
を返すもの」というルールにもそぐわないですね。
そもそも where
でチェインさせて使うものであることを考えると find_by
の結果を返すのはダメでしょう。
それでも find_by したい
そういうときはクラスメソッドを使いましょう。
def self.foo(bar)
self.find_by(bar: bar)
end
きちんと理解して scope とクラスメソッドを使い分けたいですね。