ruby-on-rails – AcitveRecord不会使用嵌套的现有记录来接受新的关联记录的accept_nested_attributes_

ActiveRecord似乎并不理解,给定具有嵌套属性的现有记录的一组参数,它可以创建一个新的嵌套记录,该记录本身具有嵌套的现有记录. (关系树:现有 – >新 – >现有)

这是一个错误,还是我错过了什么?

让我举个简单的例子.

这是我的模特:

class User < ActiveRecord::Base
  has_many :posts
  attr_accessible :name,:posts_attributes
  accepts_nested_attributes_for :posts
end

class Post < ActiveRecord::Base
  belongs_to :group
  belongs_to :user
  attr_accessible :content,:title,:group_attributes
  accepts_nested_attributes_for :group
end

class Group < ActiveRecord::Base
  has_many :posts
  attr_accessible :name
end

我在每个表中都创建了一条记录,并相应地将它们相关联,因此每个表中都有一条id = 1的记录 – 这是已知的.现在,如果我有一个现有用户,一个新帖子和一个现有组,并尝试使用accepts_nested_attributes_for更新该记录,它不喜欢它:

1.9.3-p125 :044 > params
{
                  :id => 1,:name => "Billy",:posts_attributes => [
        [0] {
                          :title => "Title",:content => "Some magnificent content for you!",:group_attributes => {
                  :id => 1,:name => "Group 1"
            }
        }
    ]
}
1.9.3-p125 :045 > u
#<User:0x00000002f7f380> {
            :id => 1,:created_at => Fri,03 Aug 2012 20:21:37 UTC +00:00,:updated_at => Fri,03 Aug 2012 20:21:37 UTC +00:00
}
1.9.3-p125 :046 > u.update_attributes params
   (0.1ms)  begin transaction
   (0.1ms)  rollback transaction
ActiveRecord::RecordNotFound: Couldn't find Group with ID=1 for Post with ID=
  from /home/trevor/.rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.7/lib/active_record/nested_attributes.rb:462:in `raise_nested_attributes_record_not_found'
  from /home/trevor/.rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.7/lib/active_record/nested_attributes.rb:332:in `assign_nested_attributes_for_one_to_one_association'
  from /home/trevor/.rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.7/lib/active_record/nested_attributes.rb:288:in `group_attributes='
  from /home/trevor/.rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.7/lib/active_record/attribute_assignment.rb:94:in `block in assign_attributes'
  from /home/trevor/.rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.7/lib/active_record/attribute_assignment.rb:93:in `each'
  from /home/trevor/.rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.7/lib/active_record/attribute_assignment.rb:93:in `assign_attributes'
  from /home/trevor/.rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.7/lib/active_record/base.rb:498:in `initialize'
  from /home/trevor/.rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.7/lib/active_record/reflection.rb:183:in `new'
  from /home/trevor/.rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.7/lib/active_record/reflection.rb:183:in `build_association'
  from /home/trevor/.rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.7/lib/active_record/associations/association.rb:233:in `build_record'
  from /home/trevor/.rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.7/lib/active_record/associations/collection_association.rb:112:in `build'
  from /home/trevor/.rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.7/lib/active_record/nested_attributes.rb:405:in `block in assign_nested_attributes_for_collection_association'
  from /home/trevor/.rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.7/lib/active_record/nested_attributes.rb:400:in `each'
  from /home/trevor/.rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.7/lib/active_record/nested_attributes.rb:400:in `assign_nested_attributes_for_collection_association'
  from /home/trevor/.rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.7/lib/active_record/nested_attributes.rb:288:in `posts_attributes='
  from /home/trevor/.rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.7/lib/active_record/attribute_assignment.rb:85:in `block in assign_attributes'
  from /home/trevor/.rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.7/lib/active_record/attribute_assignment.rb:78:in `each'
  from /home/trevor/.rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.7/lib/active_record/attribute_assignment.rb:78:in `assign_attributes'
  from /home/trevor/.rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.7/lib/active_record/persistence.rb:216:in `block in update_attributes'
  from /home/trevor/.rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.7/lib/active_record/transactions.rb:295:in `block in with_transaction_returning_status'
  from /home/trevor/.rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.7/lib/active_record/connection_adapters/abstract/database_statements.rb:192:in `transaction'
  from /home/trevor/.rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.7/lib/active_record/transactions.rb:208:in `transaction'
  from /home/trevor/.rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.7/lib/active_record/transactions.rb:293:in `with_transaction_returning_status'
  from /home/trevor/.rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.7/lib/active_record/persistence.rb:215:in `update_attributes'
  from (irb):15
  from /home/trevor/.rvm/gems/ruby-1.9.3-p125/gems/railties-3.2.7/lib/rails/commands/console.rb:47:in `start'
  from /home/trevor/.rvm/gems/ruby-1.9.3-p125/gems/railties-3.2.7/lib/rails/commands/console.rb:8:in `start'
  from /home/trevor/.rvm/gems/ruby-1.9.3-p125/gems/railties-3.2.7/lib/rails/commands.rb:41:in `<top (required)>'
  from script/rails:6:in `require'
  from script/rails:6:in `<main>'1.9.3-p125 :047 >

它认为它无法找到与新​​帖子相关的组(具有已知ID).
当我从group_attributes中删除ID时,它会起作用(但它会创建一个新的组记录).
当我给posts_attributes一个ID,并从group_attributes中删除id(并再次创建一个新组)时,它可以工作.
它们都有ID时也可以使用.

这种关系正在起作用:

1.9.3-p125 :059 > p = Post.new( { group_attributes: { name: 'Testing' } } )
#<Post:0x00000004212380> {
            :id => nil,:title => nil,:content => nil,:group_id => nil,:user_id => nil,:created_at => nil,:updated_at => nil
}
1.9.3-p125 :060 > p.group
[
    [0] #<Group:0x00000004211868> {
                :id => nil,:name => "Testing",:updated_at => nil
    }
]

如果所有记录都是新记录,则在用户创建期间使用posts_attributes和group_attributes时,它也完全有效.

它不应该仍然在第一个例子中工作吗? ActiveRecord应该足够聪明才能弄明白……!

解决方法

以下是我认为正在发生的事情:您正在传递一个组的ID,向ActiveRecord指示该组存在. ActiveRecord正试图找到该组以使用group_attributes中的其他数据更新它.由于您在post_attributes中执行此操作,因此ActiveRecord尝试通过帖子和组之间的关联来查找该组.也就是说,ActiveRecord首先查找关联的组 – 其中id = post.group_id – 然后从该结果中查找ID = 1的那个.对于父关系,这可能看起来有点奇怪和笨拙,就像你的情况一样,但是我确信你可以看到这是另一个方向的有用行为,其中嵌套属性代表一个或多个潜在的多个孩子.

但是,根据post_attributes中的数据创建的post对象尚未与组关联 – post.group_id为nil.因此,当ActiveRecord执行首次搜索获取关联组时,它将显示为空.相应地,它没有在(空)结果中找到ID = 1的组.从技术上讲,记录就在那里,但在与帖子的关联方面并不存在.

你可以通过包括group_id =>证明这一点. 1在post_attributes中.我相信,如果你这样做,ActiveRecord将通过关联找到该组,然后在结果中成功地从ID = 1中选择该组,然后使用group_attributes中的附加数据更新该组.

另请注意,如果您允许用户在创建新帖子的同时更新组名称,那么在帖子中包含组内嵌组属性的唯一原因就是您要这样做.如果您要做的只是将新帖子链接到现有组,那么您只需要在post_attributes中包含group_id,就可以摆脱group_attributes.

相关文章

validates:conclusion,:presence=>true,:inclusion=>{...
一、redis集群搭建redis3.0以前,提供了Sentinel工具来监控各...
分享一下我老师大神的人工智能教程。零基础!通俗易懂!风趣...
上一篇博文 ruby传参之引用类型 里边定义了一个方法名 mo...
一编程与编程语言 什么是编程语言? 能够被计算机所识别的表...
Ruby类和对象Ruby是一种完美的面向对象编程语言。面向对象编...