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 とクラスメソッドを使い分けたいですね。