ActiveRecordのscopeではfind_byしない方がよい
find_byしてしまうと…
ActiveRecordのscopeでは、クエリの実行結果がnil
だとall
を返してしまう。
class Order < ActiveRecord::Base scope :bar, -> { find_by(foo: 'bar') } end
Order.find_by(foo: 'bar')
と同じ動きだと思ってnil
を期待すると、all
が返る。
# レコードがあるとき Order.bar => #<Order ...> # ActiveRecord::Relationではなく、インスタンスが返る # レコードがないとき Order.bar => [#<Order ...> #<Order ...> #<Order ...>] # Order.all相当の処理 Order.bar.to_sql => "SELECT * FROM [orders]" Order.bar.class => Order::Billing::Detail::ActiveRecord_AssociationRelation
(ハイライトおかしい😭)
scope
は通常ActiveRecord_AssociationRelationを返すものだが、find_by
にしてしまうと、対象レコードがある場合でもインスタンスがそのまま返ってしまう。ActiveRecord_AssociationRelationが返ると思ってチェインしようとしたらつながらない、なんてこともありそう。(要調査)
さらに、対象レコードがない場合だと、Order.all
の結果が返ってしまう。これは困る。
クラスメソッドにするとよい
find_by
と同じ動きを期待するならば、クラスメソッドにすべき。
class Order < ActiveRecord::Base def self.bar find_by(foo: 'bar') end end
※ こうなるとただfind_by
をラップしているだけのメソッドなので、そもそもメソッドとして切り出さなくてよいのかも