AcitveRecord will not accept_nested_attributes_ for new linked records with nested existing records

ActiveRecord does not seem to understand that, given the set of parameters for an existing record with nested attributes, it can create a new nested record, which itself has a nested existing record. (Relationship Tree: Existing -> New -> Existing )

Is this a mistake, or am I missing something?

Let me show you a simple example.

Here are my models:

 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 

I made one record in each table and linked them accordingly, so each table has a record in it with id=1 - this is known. Now, if I have an existing User, a new Mail, and an existing Group, and try updating this entry using accepts_nested_attributes_for , she doesn't like it:

 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 > 

He thinks that he cannot find the group (with a known identifier) ​​associated with the new Mail. It works when I remove the identifier from group_attributes (but it creates a new group entry). It works when I give posts_attributes id and remove id from group_attributes (and create a new group again). It also works when everyone has identifiers.

Relationships work:

 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 } ] 

It also works fully when using posts_attributes and group_attributes during User creation, if all posts are new.

Should it work in the first example? ActiveRecord must be smart enough to figure it out ...!

+8
ruby-on-rails activerecord nested-attributes
source share
1 answer

Here, what I think is happening: you pass in the ID for the group, indicating to ActiveRecord that the group exists. ActiveRecord is trying to find this group in order to update it with other data available in group_attributes . Since you are doing this inside post_attributes , ActiveRecord is trying to find this group through the association between the message and the group. That is, ActiveRecord first searches for a related group - where id = post.group_id - then from this result it searches for one that has ID = 1. This may seem a little strange and awkward for parent relationships, as in your case, but I'm sure that you can see that this is a useful behavior when moving in a different direction, where the nested attributes represent one or more of potentially many children.

However, your post object created from the data in post_attributes is not yet associated with the group - post.group_id - nil. Thus, when ActiveRecord performs this first search to get the associated group, it becomes empty. Accordingly, he does not find the group with ID = 1 in the (empty) results. Technically, there is a record, but it does not exist in terms of communication with the message.

You can prove this by including group_id => 1 in post_attributes. I believe that if you do this, ActiveRecord will find the group by association, and then select the group with ID = 1 from the results, successfully, and then update this group with additional data in group_attributes.

Please also note that the only reason to include nested attributes for a group inside a column, as you do, is if you allow the user to update the group name at the same time as creating a new post. If all you need to do is associate a new message with an existing group, you just need to include group_id in post_attributes, and you can get rid of group_attributes.

+4
source share

All Articles