示例场景:模型工作线程belongs_to
模型存储桶。
请参阅以下查询:
1.9.3p194 :045 > Worker.where(bucket_id: Bucket.first).count
(0.7ms) SELECT COUNT(*) FROM "workers" WHERE "workers"."bucket_id" = 1
=> 38
1.9.3p194 :046 > Worker.where(bucket_id: Bucket.first.id).count
(0.7ms) SELECT COUNT(*) FROM "workers" WHERE "workers"."bucket_id" = 1
=> 38
1.9.3p194 :047 > Worker.new bucket_id: Bucket.first
=> #<Worker id: nil, email: nil, created_at: nil, updated_at: nil, bucket_id: nil>
1.9.3p194 :048 > Worker.new bucket_id: Bucket.first.id
=> #<Worker id: nil, email: nil, created_at: nil, updated_at: nil, bucket_id: 2>
如您所见,在where
函数的情况下,传递诸如Bucket.first
之类的实例可以代替确切的id
。所以人们会认为它也适用于new
功能。相反,它默默地失败了!
为什么它以这种方式工作?
我相信这发生在ActiveRecord::P redicateBuilder中。您可以在那里看到该值是否是它将在其上调用id
的 ActiveRecord::Base 对象。new
方法不会触发此代码,因此它的行为会有所不同。
我更喜欢明确并直接传递id
。然而,在即将推出的Rails 4中,您将能够做到这一点:
Worker.where(bucket: Bucket.first).count
这与初始化非常相似:
Worker.new(bucket: Bucket.first)
通常,如果您正在设置/匹配的属性以 _id
结尾,我建议您传递id
。
更新:我还想指出,初始化将继承where
条件。所以这将在 Rails 3.2 中工作:
Worker.where(bucket_id: Bucket.first).new
我假设这最终会通过PredicateBuilder,但不确定。即使这有效,我也不推荐它。
当您使用 .new
时,您正在创建一个空白记录,但它还没有 ID。 对于活动记录,这经常用于表单。
这与.create
不同,如果给定所需的有效参数,则将创建具有 ID 的记录。 同样,选择具有 Bucket.first
的记录将获取具有 ID 的现有记录。
如果您使用 .new
,设置所需的参数,然后执行.save
您将获得一个 ID。
我了解,Bucket.first
将返回即时对象,但Bucket.first.id
只会返回即时对象的 id。
因此,当您创建Worker.new
并通过bucket_id: Bucket.first
时,另一方面,它实际上不起作用,
Worker.new bucket_id: Bucket.first.id
它将传递正确的参数以创建新的工作线程。