Scope that finds nothing or ends with .first does another lookup
結果が見つからなくてfirstメソッドで終わるとscopeが別の結果になる。
本文
Rails4.2とRuby2.2だよ。
class Car < ActiveRecord::Base scope :where_color_or_tint, ->(q) { where("color = ? OR tint = ?", q, q).limit(1).first } scope :find_color_or_tint, ->(q) { find_by("color = ? OR tint = ?", q, q) } scope :where_color, ->(q) { where(color: q).first } scope :find_color, ->(q) { find_by(color: q) }
最初に何も見つからんかったら、次にクエリが実行し、最初の値を返している(何も見つからなかったら全てを返しているの意かな?)。これは意図している?
Car.where_color_or_tint('test') Car Load (39.4ms) SELECT `cars`.* FROM `cars` WHERE (color = 'test' OR tint = 'test') ORDER BY `users`.`id` ASC LIMIT 1 Car Load (37.7ms) SELECT `cars`.* FROM `cars` => [ [0] #<Car:0x00000006bec6d8> {
Car.find_color_or_tint('test') Car Load (0.8ms) SELECT `cars`.* FROM `cars` WHERE (color = 'test' OR tint = 'test') LIMIT 1 Car Load (39.1ms) SELECT `cars`.* FROM `cars` => [ [0] #<Car:0x000000068c53b0> {
Car.where_color('test') Car Load (0.8ms) SELECT `cars`.* FROM `cars` WHERE `cars`.`color` = 'test' ORDER BY `cars`.`id` ASC LIMIT 1 Car Load (37.4ms) SELECT `cars`.* FROM `cars` => [ [0] #<Car:0x00000006806168> {
Car.find_color('test') Car Load (0.8ms) SELECT `cars`.* FROM `cars` WHERE `cars`.`color` = 'test' LIMIT 1 Car Load (38.9ms) SELECT `cars`.* FROM `cars` => [ [0] #<Car:0x00000006720550> {
クラスメソッドとして定義したらnilや[]を返す意図通りになる。
レス1
ActiveRecord::Scoping::Named で定義している、scopeメソッドが nil || all
を返すから、このような結果になっているのように見える。
あなたのケースはfirst
やfind_
byでnil
が返る。したがってすべてのレコードが得る。
first/find_by
を使用せず、レコードがない場合の結果は言うでもないがnilではない空のARオブジェクトだ。
Car.where("color = 'gold' OR tint = 'gold'") Car Load (0.3ms) SELECT "cars".* FROM "cars" WHERE (color = 'gold' OR tint = 'gold') => #<ActiveRecord::Relation []> Car.where("color = 'gold' OR tint = 'gold'").nil? => false
私が思うに、scopes
は1レコードを返すfind_byや類似メソッドと使うために作られていない。
あなたの場合はこのようなのを試すほうがたぶんより適している。
class Car < ActiveRecord::Base scope :where_color_or_tint, ->(q) { where("color = ? OR tint = ?", q, q) } def self.first_car_with_color_or_tint(q) where_color_or_tint(q).first end end
レス2
なるほど。ありがとう。
以上。