メンタルゴリラの開発ブログ

ジュニアレベルのエンジニアがノーマルレベルになるための過程を残していくブログです。

返り値がnilになり得るならscopeは使うな

アイキャッチ

事の発端

scope :showing, ->(now = Time.current) {
  where('start_at <= ?', now).where('end_at > ? OR end_at IS NULL', now)
}

のような日時指定してデータ取得するみたいなscopeを書いた。

このとき一致するものはないため結果は[]を期待していたがなぜか全件取得されていた。

不思議に思いscopeを使用せず直接クエリを発行すると期待する結果に。

なぜ???

原因

発行されたSQLを見合わせるも一言一句違わない…

なぜだ…と思いよく見たらscope指定した際のSQLの下に

Hoge Load (1.0ms)  SELECT `hoges`.* FROM `hoges`

全件取得のSQLが発行されているではないか。

scopeの挙動

scopeはActiveRecord::Relationを返す前提で設計されているらしく、結果がnilの場合全件取得される仕様になっている。

解決策

返り値がnilになり得るならおとなしくメソッド化しよう。

def self.showing
  now = Time.current
  where('start_at <= ?', now).where('end_at > ? OR end_at IS NULL', now)
end