Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I 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 referencing 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 am aware that Item.create(:owner_id => "1") would work in this case, but unfortunately this not a viable solution in my app. This is because I am adding and deleting nested attributes on the fly and, for example, need to create a new Item object with one existing Owner object and one new Owner object.

I found these links but couldn't work out if this is a feature or a bug in 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 somebody give me an idea as to how I can make this work or have I misunderstood the correct way to use 'accepts_nested_attributes_for'??

I am using Rails 3.0.5 and Ruby 1.9.2p0.

Thanks in advance.

like image 310
James Hibbard Avatar asked Jan 08 '12 10:01

James Hibbard


People also ask

What is a nested attribute?

Nested attributes are a way of applying sub-categories to your attributes. For instance, instead of having a single searchable attribute price , you may set up some sub-categories: price.net , price. gross , price. margin (note the use of 'dot notation' here to separate the parent attribute from its child).

What is Accepts_nested_attributes_for?

accepts_nested_attributes_for(*attr_names) public. Defines an attributes writer for the specified association(s). Supported options: :allow_destroy. If true, destroys any members from the attributes hash with a _destroy key and a value that evaluates to true (eg.


1 Answers

I solved the problem another way and wanted to post a simplified version of it here in case it helps anyone else. In my real app the assosciation between both resources is HABTM and the nested resource is a file attachment.

So, in the create action of the controller, I separate the parameters for the original resource and those for the nested resource.

I then further separate the nested resource into objects which exist in the database and objects which don't, putting the ids of those which do into an array.

If no existing nested objects are present, then it's plain sailing from here.

However, presuming both existing and new nested objects are present, I create a new Item object thus:
@item = Item.new(:attachment_ids => existing_attachment_ids)

After that I update @item thus:
@item.update_attributes(original_item_params)
@item.update_attributes(params_for_new_nested_objects)

Then you can call @item.save and have it re-render the view if any errors occur.

I still can't work out if this is a bug or a feature ir Rails. If anyone has any thoughts on the subject or my solution, I would be very glad to hear them.

like image 60
James Hibbard Avatar answered Nov 15 '22 04:11

James Hibbard