AcitveRecord不会为具有嵌*有记录的新关联记录accept_nested_attributes_

问题描述:

ActiveRecord似乎并不理解,给定一组具有嵌套属性的现有记录的参数,它可以创建一个新的嵌套记录,该记录本身具有嵌套的现有记录。 (关系树:Existing -> New -> ExistingAcitveRecord不会为具有嵌*有记录的新关联记录accept_nested_attributes_

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

让我给你看一个简单的例子。

这里是我的模型:

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, 
      :name => "Billy", 
    :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),与一个新的Post相关。 它可以在我从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", 
     :created_at => nil, 
     :updated_at => nil 
    } 
] 

User创建过程中使用posts_attributesgroup_attributes时,如果所有的记录都新也完全适用。

不应该在第一个例子中工作吗? ActiveRecord应该足够聪明以解决这个问题......!

+0

您在用户模型中缺少'has_many:comments'。 – jordanpg 2012-08-03 21:07:52

+0

哎呀,这个问题依然存在。 :)我会简化这个例子。 – wulftone 2012-08-03 21:17:28

+0

长问题,但新记录如何具有现有的关联? – pjammer 2012-08-03 21:25:49

以下是我认为正在发生的事情:您正在为组传递一个ID,指示ActiveRecord该组存在。 ActiveRecord正试图找到该组以使用group_attributes中的其他数据对其进行更新。既然你这样做是post_attributes,ActiveRecord的是试图通过之间的关联找到该组。也就是说,ActiveRecord首先查找关联组 - 其中id = post.group_id - 然后从该结果中查找ID = 1的组织。对于父母关系来说,这看起来有点奇怪和笨拙,就像你的情况一样。我相信你可以看到,在朝着另一个方向前进时这是有用的行为,其中嵌套属性表示一个或多个潜在的许多孩子。

但是,根据post_attributes中的数据创建的发布对象尚未与组关联 - post.group_id为零。所以,当ActiveRecord首先进行搜索以获取关联组时,它就会变空。相应地,它在(空)结果中找不到ID = 1的组。从技术上讲,该记录在那里,但在之后,它不存在

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

还要注意的是,只有原因包括嵌套属性的组内后,就像你正在做的是,如果你是允许用户在创建一个新的职位的同时更新组名。如果您所要做的只是将新帖子链接到现有的群组,那么您只需要在post_attributes中包含group_id,并且可以摆脱group_attributes。

+0

这对我来说似乎很合理,但这种情况早已消失。 :)我确实记得我_did_想同时更新关联和根记录上的属性(我没有使用这些确切的User,Post和Group表,但它是一个类似的结构)。我认为做这样一个行动的必要性被放在了未来实施的后面,然后被遗忘了。它可能会回来困扰我们!感谢您的回答。当我再次遇到这个问题时,我一定会参考它。 – wulftone 2013-11-14 20:37:55

+0

再试一次,即使我在Post中有一个'group_id',我也会创建新的'Groups' - 尽管它不会引发错误。它只是忽略'group_id'并且创建一个。仍然似乎不可能做到。 – wulftone 2013-11-14 21:24:02

+0

该死的。真的以为我有那个钉子。我会花一些时间在本周末讨论这个场景,看看我能想出什么,现在它一直停留在我身上。 ;) – Yardboy 2013-11-15 14:08:15