29

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

post.tags << Tag.first

这将立即提交到数据库。我尝试了其他方法而不是<<,但没有成功(我想要的是在保存父对象时创建关联)。是否有可能获得像当您通过构建向新记录添加关联时的行为?

post.tags.build name: "whatever"

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

换句话说我想要

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

4 回答 4

36

这应该适用于 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
于 2014-06-25T20:50:51.437 回答
3
post_tag = post.post_tags.find_or_initialize_by_tag_id(Tag.first.id)
post_tag.save
于 2013-11-12T04:16:40.390 回答
2

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

于 2018-09-28T18:29:27.727 回答
0

前言 这并不完全是对这个问题的回答,但是搜索这种功能的人可能会发现这很有用。在大肆将其放入生产环境之前,请仔细考虑此选项和其他选项。

在某些情况下,您可以利用 has_one 关系来获得您想要的。同样,在使用它之前,请真正考虑您要完成的工作。

要考虑的代码 你有一个has_many关系 from TrunktoBranch并且你想添加一个新的分支。

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与 a 建立更合理的关系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 中要求的功能。

于 2016-07-30T20:16:31.333 回答