save していない ActiveRecord インスタンスで、親知らずな子レコードが取得される
save していない ActiveRecord インスタンスで、association メソッドと、association 先の scope を chain した際の挙動に違和感を感じたので書いてみます
# Rails 3.2.3 で試しています
Model を用意して、
class Firm < ActiveRecord::Base has_many :clients end
class Client < ActiveRecord::Base belongs_to :firm end
データを作成します
firm = Firm.create! name: '37signals' # => #<Firm id: 1, name: "37signals"> firm.clients << Client.new(name: 'WWF') # => [#<Client id: 1, name: "WWF", firm_id: 1>] firm.clients << Client.new(name: 'patagonia') # => [#<Client id: 1, name: "WWF", firm_id: 1>, #<Client id: 2, name: "patagonia", firm_id: 1>]
この状態で、Firm#clients を実行した結果は以下です
firm.clients
# => [#<Client id: 1, name: "WWF", firm_id: 1>, #<Client id: 2, name: "patagonia", firm_id: 1>]
つぎは、order という scope を chain して実行した結果です
firm.clients.order :name # => [#<Client id: 2, name: "patagonia", firm_id: 1>, #<Client id: 1, name: "WWF", firm_id: 1>]
"association メソッドと、association 先の scope を chain した" というのはこのケースをいっています
ここまでは、まったくイメージ通りで、問題なしです
つぎに、少しデータを編集します
firm.clients = []
# => []
上を実行すると内部的には以下の SQL が実行され
UPDATE `clients` SET `firm_id` = NULL WHERE `clients`.`firm_id` = 1 AND `clients`.`id` IN (1, 2)
"37signals" の clients として、"WWF", "patagonia" は参照できない状態になります
この状態で以下を実行した場合の結果は何でしょうか?
Firm.new.clients
空の配列です
# => []
では、以下を実行した結果は何でしょうか?
Firm.new.clients.order :name
んんん、以下になりますー
# => [#<Client id: 2, name: "patagonia", firm_id: nil>, #<Client id: 1, name: "WWF", firm_id: nil>]
改めて実行してみると、違和感どころの騒ぎじゃないような
実行される SQL は、以下となっていて気持ちは伝わってきますが、こちらの気持ちは汲み取ってもらえていないですね
SELECT `clients`.* FROM `clients` WHERE `clients`.`firm_id` IS NULL ORDER BY name
ちなみに、
Rails 2.3.14 で、同じことをすると イメージ通りの結果がかえります
# order という scope は、Client に自前で実装している前提です
Firm.new.clients.order :name # => []
実行される SQL は以下となっています
SELECT * FROM `clients` WHERE (`clients`.firm_id = NULL) ORDER BY name
どっちにしても、
データベースに保存されていないインスタンスが、association メソッドを実行する場合、データベースへの問い合わせは必要ないんじゃないだろうか