3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【Ruby on Rails】Model の scope で find_by するのはNG

Posted at

scope の罠

先日以下のような scope を見ました。

user.rb
class User < ActiveRecord::Base
  scope :foo, -> (bar) do
    return if bar.nil?
    find_by(bar: bar)
  end
end

もちろん使い方しだいではありますが、この動き、ちょっと想定外だったりするので注意です。

barnilreturn される場合 (nil が返る)、
find_by で見つからなくて nil になる場合、

このとき、scope の戻りは nil ではありません。

User.foo(nil) は nil ではありません。

User.all が返ります。

(正確には default scope が返る)

なぜ nil が返らないのか

どうやら scopeActiveRecord::Relation を返すものだと決まっているよう。
なのでnilが返るときは default scope である User.all を返すようです。

以下の記事が理解しやすかったです。

User.foo.where(baz: baz)

のようにチェインすることを考えると、たしかに nil で返ると困りますね。

じゃぁ find_by すべきではないんじゃ?

find_by して得られるのはそのモデルクラスのインスタンス(またはnil)なので、「scopeActiveRecord::Relation を返すもの」というルールにもそぐわないですね。

そもそも where でチェインさせて使うものであることを考えると find_by の結果を返すのはダメでしょう。

それでも find_by したい

そういうときはクラスメソッドを使いましょう。

def self.foo(bar)
  self.find_by(bar: bar)
end

きちんと理解して scope とクラスメソッドを使い分けたいですね。

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?