示例场景:
模型工人belongs_to
模型Bucket。
请参阅以下查询:
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
函数。相反,它无声地失败!
为什么这样做?
答案 0 :(得分:3)
我相信这发生在ActiveRecord::PredicateBuilder。如果值是ActiveRecord :: Base对象,您可以在其中看到它将在其上调用id
。 new
方法不会触发此代码,因此它的行为会有所不同。
我更喜欢明确并直接传递id
。但是upcoming in 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,但不确定。即使这有效,我也不推荐它。
答案 1 :(得分:0)
根据我的理解,Bucket.first
会返回一个即时对象,但Bucket.first.id
只会返回即时对象的ID。
因此,当您创建Worker.new
并传递bucket_id: Bucket.first
时,实际上它将无效,
Worker.new bucket_id: Bucket.first.id
它将传递正确的参数以创建新的Worker。
答案 2 :(得分:0)
当您使用.new
时,您正在创建一个空白记录,但它还没有ID。使用Active Record时,这经常用于表单。
这与.create
不同,如果给定所需的有效参数,则会创建带有ID的记录。同样,选择带有Bucket.first
的记录会获得具有ID的现有记录。
如果您使用.new
,请设置所需参数,然后执行.save
,然后您将获得一个ID。