5

外部キーとしてNULLを持つモデルが何かに属することは期待していません!

私は次のレールアプリを持っています。アリとアリの丘をモデリングしています(Jozefに触発されました)。

$ rails -v
Rails 3.2.8
$ rails new ant_hill
$ cd ant_hill

蟻の丘と蟻のモデルを作成します。アリはアリの丘に属することができ、アリの丘は多くのアリを持つことができます。

$ rails generate model AntHill name:string
$ rails generate model Ant name:string ant_hill_id:integer
$ vim app/models/ant.rb
$ cat app/models/ant.rb
class Ant < ActiveRecord::Base
  belongs_to :ant_hill
end
$ vim app/models/ant_hill.rb
$ cat app/models/ant_hill.rb
class AntHill < ActiveRecord::Base
  has_many :ants
end
$ rake db:migrate
==  CreateAntHills: migrating =================================================
-- create_table(:ant_hills)
   -> 0.0013s
==  CreateAntHills: migrated (0.0016s) ========================================

==  CreateAnts: migrating =====================================================
-- create_table(:ants)
   -> 0.0035s
==  CreateAnts: migrated (0.0037s) ============================================

コンソールで次のコードを実行します。

$ rails c
Loading development environment (Rails 3.2.8)

どのアリの丘にも属さない、永続的なアリをいくつか作成します。

1.9.2-p290 :001 > Ant.create! name: "August"
 => #<Ant id: 1, name: "August", ant_hill_id: nil, created_at: "2012-09-27 12:01:06", updated_at: "2012-09-27 12:01:06">
1.9.2-p290 :002 > Ant.create! name: "Bertil"
 => #<Ant id: 2, name: "Bertil", ant_hill_id: nil, created_at: "2012-09-27 12:01:13", updated_at: "2012-09-27 12:01:13">

次に、蟻の丘をインスタンス化しますが、まだ保存しないでください。

1.9.2-p290 :003 > ant_hill = AntHill.new name: "Storkullen"
 => #<AntHill id: nil, name: "Storkullen", created_at: nil, updated_at: nil>

この蟻の丘には蟻がいないと思いますが、ありません。

1.9.2-p290 :004 > ant_hill.ants
 => []

私はまだ蟻の丘に蟻がいないことを期待していますが、今では2つあります。

1.9.2-p290 :005 > ant_hill.ants.count
   (0.1ms)  SELECT COUNT(*) FROM "ants" WHERE "ants"."ant_hill_id" IS NULL
 => 2

ここでも同じですが、外部キーを処理するときに「ISNULL」を含むクエリを生成することはできません。「belongs_toNULL」は何にも属せないということですね。

1.9.2-p290 :006 > ant_hill.ants.all
  Ant Load (0.4ms)  SELECT "ants".* FROM "ants" WHERE "ants"."ant_hill_id" IS NULL
 => [#<Ant id: 1, name: "August", ant_hill_id: nil, created_at: "2012-09-27 12:01:06", updated_at: "2012-09-27 12:01:06">, #<Ant id: 2, name: "Bertil", ant_hill_id: nil, created_at: "2012-09-27 12:01:13", updated_at: "2012-09-27 12:01:13">]

永続化された後、期待どおりに動作します。

1.9.2-p290 :007 > ant_hill.save!
 => true
1.9.2-p290 :008 > ant_hill.ants.count
   (0.4ms)  SELECT COUNT(*) FROM "ants" WHERE "ants"."ant_hill_id" = 1
 => 0
1.9.2-p290 :009 > ant_hill.ants.all
  Ant Load (0.4ms)  SELECT "ants".* FROM "ants" WHERE "ants"."ant_hill_id" = 1
 => []

何か洞察はありますか?これは予想される動作ですか?

4

1 に答える 1

1

直感に反するように思えますが、あなたの例を考えると、この動作は理にかなっていると思います。例を挙げてみましょうant_hill.ants.count。Count は、データベースにアクセスする ActiveRecord クエリ メソッドです。基本的には、ActiveRecord に、アリ塚に属していないすべてのアリを取得するように要求しています。Rails は、できるはずのないことを単純にさせてくれるものであり、それについて不平を言うのではありません。これは代わりに例外を発生させるべきですか? おそらく。

この ant_hill オブジェクトに属するアリの数を本当に知りたい場合は、サイズを使用する必要があります。永続化されていない場合、または関連付けが既に読み込まれている場合はオブジェクトを照会し、それ以外の場合はデータベースを照会します。

ant_hill.ants.size

この奇妙な点を回避する方法の 1 つは、ant_hill_id の存在を検証して必須フィールドにすることです。

TL;DR 親オブジェクトがデータベースに永続化されていない場合は、ActiveRecord クエリ インターフェイスを使用しないでください。

于 2012-09-27T12:58:56.417 に答える