在Rails 3中构建与新


125

在Rails 3 文档中build关联方法被描述为与new方法相同,但是具有自动分配外键的功能。直接来自文档:

Firm#clients.build (similar to Client.new("firm_id" => id))

我在其他地方也读过类似的文章。

但是,当我使用new(例如,some_firm.clients.new不带任何参数)时,自动创建新客户端的firm_id关联。我现在正在控制台中盯着结果!

我想念什么吗?文档是否有点过时(不太可能)?build和之间有什么区别new


3
人们正在寻找快速答案,请检查第二个答案:“ build”只是“ new”的别名
ivanreese 2016年

Answers:


208

您稍微误读了文档。some_firm.client.new正在Client从客户集合中创建一个新对象,因此它可以自动将设置firm_idsome_firm.id,而文档正在调用,而该Client.new对象根本不知道任何公司的ID,因此需要将其firm_id传递给它。

some_firm.clients.new和之间的唯一区别some_firm.clients.build似乎是,它build还将新创建的客户端添加到clients集合中:

henrym:~/testapp$ rails c
Loading development environment (Rails 3.0.4)
r:001 > (some_firm = Firm.new).save # Create and save a new Firm
#=> true 
r:002 > some_firm.clients           # No clients yet
#=> [] 
r:003 > some_firm.clients.new       # Create a new client
#=> #<Client id: nil, firm_id: 1, created_at: nil, updated_at: nil> 
r:004 > some_firm.clients           # Still no clients
#=> [] 
r:005 > some_firm.clients.build     # Create a new client with build
#=> #<Client id: nil, firm_id: 1, created_at: nil, updated_at: nil> 
r:006 > some_firm.clients           # New client is added to clients 
#=> [#<Client id: nil, firm_id: 1, created_at: nil, updated_at: nil>] 
r:007 > some_firm.save
#=> true 
r:008 > some_firm.clients           # Saving firm also saves the attached client
#=> [#<Client id: 1, firm_id: 1, created_at: "2011-02-11 00:18:47",
updated_at: "2011-02-11 00:18:47">] 

如果要通过关联创建对象,build则应优先考虑new构建,因为some_firm即使在将任何对象保存到数据库之前,构建仍将内存中的对象(在这种情况下)保持一致的状态。


8
使用some_firm.client.new也增加了客户端some_firm.clients,并呼吁savesome_firm造成这表明验证错误client是无效的。如果两者都将newbuild并将新客户端添加到some_firm的客户端集合中,那build怎么new办呢?很抱歉,我在这里!
ClosureCowboy 2011年

1
+1我收到了3.0.4的结果。如果3.0.3版本的使用者可以确认我没有疯,我会很乐意。
ClosureCowboy 2011年

41
@henrym在3.2.6中,clients.new和clients.build看起来很相似,因为它们都将新对象添加到集合中。我想为像我一样在谷歌搜索时遇到此问题的人添加评论
哈伯德(Hubbard)2012年

11
看起来它们在Rails 3.2.3中没有什么区别
Aditya Kapoor 2012年

4
对于Rails> 3.2.13,此答案是不正确的,其中“ build”只是“ new”的别名。请参阅下面的@HatemMahmoud答案。
安德里亚斯(Andreas)

91

build只是以下项的别名new

alias build new

可以找到完整的代码:https : //github.com/rails/rails/blob/master/activerecord/lib/active_record/relation.rb#L74


13
alias build new从rails 3.2.13起
fontno

7
这仅在某些关联/关系中适用。例如,单数关联对build和具有完全不同的定义build_#{association}。看到这里这里
coreyward 2014年

1
这仍然适用Rails 4吗?
fatman13年

1
是错误报告...这建议您是否使用了诸如restaurant.customers.new之类的新方法,以此作为获得与餐厅关联的新客户而不将其附加到restaurant.customers的一种方式,以使用范围...如restaurant .customers.scoped.new
2014年

11

您是正确的,当通过关联调用构建函数和新函数时,它们具有与设置外键相同的效果。我相信这样写文档的原因是为了阐明正在实例化一个新的Client对象,而不是一个新的活动记录关系。这与在类中调用.new的效果相同。也就是说,文档澄清了在关联上调用构建是在创建一个新对象(调用.new)并将外键传递给该对象一样。这些命令都是等效的:

Firm.first.clients.build
Firm.first.clients.new
Client.new(:firm_id => Firm.first.id)

我相信存在.build的原因是Firm.first.clients.new可能被解释为意味着您正在创建一个新的has_many关系对象,而不是实际的客户端,因此调用.build是一种澄清方法。


因此它们等效的。这绝对是看起来。谢谢!
ClosureCowboy 2011年

5
这是不正确的。前两个版本在Rails的更高版本中是等效的(看起来好像在发布时不一样)。但是,最后一个有很大的不同,即Firm.first.clients将不包含新客户端。
tybro0103

4

buildvs new

大多数是与new相同的,但是build将对象存储在内存中

例如:

对于新的:

Client.new(:firm_id=>Firm.first.id)

对于构建:

Firm.first.clients.build

客户端存储在内存中,保存公司时,还将保存相关记录。


2

新模型

Tag.new post_id: 1将实例化带有其post_id集合的Tag 。

@ model.models.new

@post.tags.build执行相同的操作并且实例化的Tag @post.tags甚至在保存之前就已经存在。

这意味着@post.save将同时保存@post和新建标签(假设设置了:inverse_of)。这很棒,因为Rails将在保存之前验证两个对象,并且如果其中任何一个验证失败,则不会保存任何对象。

models.new与models.build

@post.tags.build@post.tags.new等效(至少从Rails 3.2起)。


怎么样The only difference between some_firm.clients.new and some_firm.clients.build seems to be that build also adds the newly-created client to the clients collection:
アレックス
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.