添加关联(<<)而不提交数据库

在Rails中是否可以在不立即将此更改提交到数据库的情况下向现有记录添加关联? 例如,如果我有Post has_many:标签

post.tags << Tag.first 

这将立即提交到数据库。 我尝试过其他方式而不是<<,但没有成功(我想要的是在保存父对象时创建关联)。 是否有可能获得类似于使用build添加新记录的关联时的行为?

 post.tags.build name: "whatever" 

我认为这在Rails中有点不一致,在某些情况下,选择执行此操作会很有用。

换句话说我想要

 post.tags << Tag.first # don't hit the DB here! post.save # hit the DB here! 

这应该适用于Rails 3.2和Rails 4:

 post.association(:tags).add_to_target(Tag.first) 

请参阅此要点: https : //gist.github.com/betesh/dd97a331f67736d8b83a

请注意,保存父级会保存子级,并且在保存之前不会设置child.parent_id。

编辑12/6/2015:对于多态记录:

 post.association(:tags).send(:build_through_record, Tag.first) # Tested in Rails 4.2.5 
 post_tag = post.post_tags.find_or_initialize_by_tag_id(Tag.first.id) post_tag.save 

要添加到Isaac的答案, post.association(:tags).add_to_target(Tag.first)适用于has_many关系,但您可以对has_one关系使用post.association(:tag).replace(Tag.first, false) 。 第二个参数( false )告诉它不要保存; 如果将参数留空,它会默认将其提交到数据库。

前言这不是这个问题的答案,但是搜索这种function的人可能会觉得这很有用。 在大肆投入生产环境之前,请仔细考虑这个和其他选项。

在某些情况下,您可以利用has_one关系来获得所需内容。 再次,在使用它之前,请真正考虑您要完成的任务。

要考虑的代码您从TrunkBranch有一个has_many关系,并且您想要添加一个新分支。

 class Trunk has_many :branches end class Branch belongs_to :trunk end 

我也可以将它们彼此联系起来。 我们将向Trunk添加has_one关系

 class Trunk has_many :branches has_one :branch end 

此时,您可以执行Tree.new.branch = Branch.new并且您将设置一个不会立即保存的关系,但是在保存之后,将从Tree.first.branches

然而 ,对于新开发人员来说,当他们看到代码时会想到这样一个令人困惑的情况并且想:“好吧,它到底应该是哪一个,一个或多个?”

为了解决这个问题,我们可以与scope建立更合理的has_one关系。

 class Trunk has_many :branches # Using timestamps has_one :newest_branch, -> { newest }, class_name: 'Branch' # Alternative, using ID. Side note, avoid the railsy word "last" has_one :aftmost_branch, -> { aftmost }, class_name: 'Branch' end class Branch belongs_to :trunk scope :newest, -> { order created_at: :desc } scope :aftmost, -> { order id: :desc } end 

小心这一点,但它可以完成OP中要求的function。