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

时间:2012-11-02 14:36:15

标签: ruby-on-rails ruby-on-rails-3

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

post.tags << Tag.first

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

post.tags.build name: "whatever"

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

换句话说,我想要

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

4 个答案:

答案 0 :(得分:31)

这应该适用于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

答案 1 :(得分:3)

post_tag = post.post_tags.find_or_initialize_by_tag_id(Tag.first.id)
post_tag.save

答案 2 :(得分:2)

要添加以撒的答案,<!DOCTYPE html> <html> <head> <title>Title of the document</title> <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.min.js"></script> </head> <body> <canvas id="myChart" width="400" height="400"></canvas> </body> </html>适用于post.association(:tags).add_to_target(Tag.first)关系,但是您可以将has_many用于post.association(:tag).replace(Tag.first, false)关系。第二个参数(has_one告诉它不保存;如果您将该参数保留为空,它将默认将其提交到数据库。

答案 3 :(得分:0)

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

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

要考虑的代码 您与has_manyTrunk之间存在Branch关系,并且您想要添加新分支。

class Trunk
  has_many :branches
end

class Branch
  belongs_to :trunk
end

我也可以将它们彼此联系起来。我们会向has_one

添加Trunk关系
class Trunk
  has_many :branches
  has_one :branch
end

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

然而,这让新开发人员在查看代码并认为“嗯,它到底应该是哪一个,一个或多个?”时会造成相当混乱的情况。

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

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中要求的功能。