我不希望一个名为NULL的模型作为外键属于任何东西!
我有以下rails应用程序,模拟蚂蚁和蚂蚁山(灵感来自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
=> []
我仍然希望蚂蚁山没有任何蚂蚁,但现在有两只蚂蚁。
1.9.2-p290 :005 > ant_hill.ants.count
(0.1ms) SELECT COUNT(*) FROM "ants" WHERE "ants"."ant_hill_id" IS NULL
=> 2
同样,它永远不应该生成包含&#34; IS NULL&#34;的查询。处理外键时。我是说&#34; belongs_to NULL&#34;什么都不属于,对吗?
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
=> []
有什么见解?这是预期的行为吗?
答案 0 :(得分:1)
虽然这似乎违反直觉,但我认为这种行为在你的例子中是有道理的。以ant_hill.ants.count
为例。 Count是一个命中数据库的ActiveRecord查询方法,你基本上要求ActiveRecord为你提供所有不属于蚂蚁山的蚂蚁。 Rails只是让你做一些你不应该做的事情,而不是抱怨它。这应该引发异常吗?可能。
如果你真的想知道有多少蚂蚁属于这个ant_hill对象,你应该使用大小。它在未持久化或已加载关联时查询对象,否则查询数据库。
ant_hill.ants.size
你可以通过验证它的存在来使ant_hill_id成为必填字段。
TL; DR如果父对象未持久保存到数据库,则避免使用ActiveRecord查询接口。