29

我有一个用户和嵌套的配置文件类,如下所示:

class User < ActiveRecord::Base
  has_one :profile
  attr_accessible :profile_attributes
  accepts_nested_attributes_for :profile
end

class Profile < ActiveRecord::Base
  belongs_to :user
  attr_accessible :name
end

user = User.find(1)
user.profile.id  # => 1
user.update_attributes(profile_attributes: {name: 'some name'})
user.profile.id  # => 2

我不明白为什么 rails 会丢弃旧的配置文件并创建一个新的配置文件。

使用

user.profile.update_attributes({name: 'some name'})

只是按预期更新当前配置文件。但在那种情况下,我没有利用 Accept_nested_attributes_for

有谁知道为什么更新会以这种方式发生?我不希望最终得到一个未连接到任何用户的配置文件行数据库。

4

4 回答 4

37

对于在 Rails 4 中遇到相同问题的每个人:fields_for 已经为嵌套表单添加了 id,但您必须允许 :id 参数。我只允许一个 :object_name_id 参数,因为这不会引发任何错误,所以我花了一些时间才在服务器日志中看到它。希望这有助于有人在这方面浪费的时间比我少:)

于 2013-11-02T13:48:49.033 回答
24

如果您检查表单,则需要在 Profile 对象的嵌套属性哈希中设置 id 属性。如果没有设置 id,ActiveRecord 会假定它是一个新对象。

例如,如果您有一个 ERB 表单为用户内的嵌套配置文件构建一组“用户”参数,其中包含嵌套的“profile_attributes”参数哈希,则可以为配置文件 ID 包含一个隐藏值,如下所示:

<%= hidden_field "user[profile_attributes][id]", @profile.id %>
于 2012-03-30T18:26:06.313 回答
21

我通过添加update_only选项解决了这个问题:

accepts_nested_attributes_for :profile, update_only: true

现在,只有在尚不存在的情况下才会创建新的配置文件。

于 2012-04-04T14:16:30.903 回答
0

我在另一个版本的 Rails 中遇到了这个问题,我以为我会失去理智。虽然添加 update_only => true 解决了它,但我认为这是 Rails 中的某个错误。

在我的情况下的症状:我会获得与 belongs_to 删除的关联并创建新的嵌套对象 - 直到我第一次刷新页面。之后它工作正常。

就我而言,我在嵌套类中添加了一个 before_save 方法并打印了它保存的内容。我还在调用 update_attributes 之前打印了属性。他们正确设置了“parent_id”。我还在表单中包含了隐藏的 id 字段,没有变化 - 这是正常的,因为它已经通过使用 fields_for...

惊喜:我看到一个更新调用生成了两个保存调用。第一次保存将具有嵌套对象 id,但为 belongs_to id 为空。- 所以这将更新记录以将“parent_id”设置为空。第二个保存将设置“parent_id”,但它会将嵌套对象 id 设置为 null。

正如我所说,我通过添加 update_only => true 来修复它,但我认为它仍然是一个错误。

我想知道上述症状是否也适用于您的情况,以确认这是一个错误。

于 2016-03-01T16:10:53.337 回答