How to create a new object referencing an existing nested attribute?

I have an Item resource and an Owner resource.

rails g scaffold Item name:string rails g scaffold Owner name:string class Item < ActiveRecord::Base has_one :owner accepts_nested_attributes_for :owner end class Owner < ActiveRecord::Base belongs_to :item end 

My problem is that I cannot create a new Item object that references an existing Owner object.

 In /db/migrate/create_owners.rb def self.up ... t.integer :item_id end rake db:migrate rails c ruby-1.9.2-p0 > o= Owner.create(:name => "Test") => #<Owner id: 1, name: "Test", created_at: "...", updated_at: "..."> ruby-1.9.2-p0 > i= Item.create(:owner_attributes => {"id" => Owner.last.id.to_s}) ActiveRecord::RecordNotFound: Couldn't find Owner with ID=1 for Item with ID= 

I know that Item.create(:owner_id => "1") will work in this case, but unfortunately this is not a viable solution in my application. This is because I add and remove nested attributes on the fly and, for example, you need to create a new Item object with one existing Owner object and one new Owner object.

I found these links, but could not figure out if this is a feature or an error in the rails:
https://rails.lighthouseapp.com/projects/8994/tickets/4254-assigning-nested-attributes-fails-for-new-object-when-id-is-specified
http://osdir.com/ml/RubyonRails:Core/2011-05/msg00001.html

Can someone give me an idea of ​​how I can do this work, or did I misunderstand the correct way to use "accepts_nested_attributes_for" ??

I am using Rails 3.0.5 and Ruby 1.9.2p0.

Thanks in advance.

+6
source share
4 answers

When trying to create an Item with an owner ID in the nested attributes, it tells ActiveRecord to update the existing Owner record. ActiveRecord cannot find the Owner record because there is no existing foreign key value (the id for the element record is still zero).

 Item.create(:owner_attributes => {"id" => Owner.last.id.to_s}) #=> ActiveRecord::RecordNotFound: Couldn't find Owner with ID=1 for Item with ID= 

Try exchanging has_one / belongs_to links and moving the foreign key to the element table. Then you can set the foreign key in the parent (non-nested) model and still use the nested attributes.

 class Item < ActiveRecord::Base belongs_to :owner accepts_nested_attributes_for :owner end class Owner < ActiveRecord::Base has_one :item end owner = Owner.create Item.create(:owner_id => owner.id, :owner_attributes => {"id" => owner.id, ...}) #=> Works!!! Note that the owner id is used twice. With some work you could probably set the id in one place or the other. 
+1
source

I solved the problem differently and wanted to post a simplified version of this here if it helps someone else. In my real application, the association between both resources is HABTM, and the attached resource is the file attachment.

So, in the action of creating the controller, I separate the parameters for the source resource and those specified for the embedded resource.

Then I further divide the embedded resource into objects that exist in the database and objects that do not, putting the identifiers of those that do in the array.

If there are no existing nested objects, then it just floats from here.

However, if there are both existing and new nested objects, I create a new Item object this way:
@item = Item.new(:attachment_ids => existing_attachment_ids)

After that, I update @item like this:
@item.update_attributes(original_item_params)
@item.update_attributes(params_for_new_nested_objects)

You can then call @item.save and re-display the view if any errors occur.

I still cannot figure out if this is a bug or an ir Rails function. If anyone has thoughts on this issue or my decision, I would be very happy to hear them.

+2
source

accepts_nested_attributes_for used only for has_one and has_many associations. (see http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html no belongs_to) It's called "nested", so it doesn't help much. Perhaps reorganizing your application?

In particular, the case of the error you are encountering is that it expects the parent to be able to find the nested model, given the identifier of the nested model. I.e.

 parent.nested_model.find(id) 

This is there, it seems, mainly to stop from updating child models that do not belong to the parent

0
source

So I achieved something similar, but not perfect. Take a look! My test fails, though now, because I don't know Factory Girl better.

creation of an object with the results of the has_many association in an element cannot be empty

0
source

Source: https://habr.com/ru/post/905439/


All Articles