2012-01-08 9 views
6

Tengo un recurso de artículo y un recurso de propietario.¿Cómo creo un nuevo objeto que haga referencia a un atributo anidado existente?

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 

Mi problema es que no puedo crear un nuevo objeto Item que haga referencia a un objeto propietario existente.

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= 

Soy consciente de que Item.create(:owner_id => "1") funcionaría en este caso, pero por desgracia no esta una solución viable en mi aplicación. Esto se debe a que estoy agregando y eliminando atributos anidados sobre la marcha y, por ejemplo, necesito crear un nuevo objeto Item con un objeto Owner existente y un nuevo objeto Owner.

He encontrado estos enlaces, pero no pude averiguar si se trata de una característica o un error en rieles:
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

Puede alguien dar una idea de cómo puedo hacer este trabajo o ¿He entendido mal la forma correcta de usar 'accepts_nested_attributes_for'?

Estoy usando Rails 3.0.5 y Ruby 1.9.2p0.

Gracias de antemano.

Respuesta

1

Cuando intenta crear una Item con el identificador de propietario en los atributos anidados, se dice ActiveRecord para actualizar un registro existente Owner. ActiveRecord no puede encontrar el registro de Propietario porque no existe un valor de clave externa (el id para el registro de elemento sigue siendo nulo).

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

intentar cambiar la has_one/belongs_to associtaions y mover la clave externa a la tabla de artículos. Luego puede establecer la clave externa en el modelo principal (no anidado) y aún usar los atributos anidados.

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. 
+0

Gracias! No he trabajado en este proyecto por más de un año, pero tu respuesta tiene sentido. Lo probaré (sin interés) cuando tenga un momento. –

0

accepts_nested_attributes_for solo se usa para has_one y has_many asociaciones. (Consulte http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html no belongs_to) Se llama 'anidado', por lo que no hay mucha ayuda allí. Tal vez refactorizar su aplicación?

Específicamente el caso de error que está encontrando es porque espera que el padre pueda encontrar el modelo anidado, dado el id del modelo anidado. Es decir.

parent.nested_model.find(id) 

Está ahí parece, básicamente para evitar que la actualización de modelos de los niños que no pertenecen al padre

+0

Gracias. Cambié el ejemplo para usar has_one. Lamentablemente, el problema persiste. ¿Hay alguna manera de lograr lo que estoy intentando, o es mejor que regrese a la mesa de dibujo? –

+0

No es cierto, funcionará para belongs_to, simplemente no hay un ejemplo de ello allí. Si has_one funciona, el belongs_to también funcionará. –

+0

@RyanBigg hmm, debo haber leído mal cómo funciona anidado. sí 'belongs_to' debería funcionar si has_one funciona. @Jack no, parece que es un problema como el enlace del faro (https://rails.lighthouseapp.com/projects/8994/tickets/4254-assigning-nested-attributes-fails-for-new-object-when-id- is-specified # ticket-4254-6) que ha publicado. –

2

He resuelto el problema de otra manera y quería publicar una versión simplificada de aquí en caso de que ayuda a cualquier otra persona En mi aplicación real, la asociación entre ambos recursos es HABTM y el recurso anidado es un archivo adjunto.

Por lo tanto, en la acción create del controlador, separé los parámetros para el recurso original y los del recurso anidado.

Luego, se separa el recurso anidado en objetos que existen en la base de datos y los objetos que no lo hacen, poniendo los identificadores de aquellos que sí lo hacen en una matriz.

Si no hay objetos anidados existentes, entonces es fácil navegar desde aquí.

Sin embargo, suponiendo que ambos objetos anidados existentes y nuevos están presentes, puedo crear un nuevo objeto de artículo así:
@item = Item.new(:attachment_ids => existing_attachment_ids)

Después de que actualice el @item así:
@item.update_attributes(original_item_params)
@item.update_attributes(params_for_new_nested_objects)

A continuación, puede llamar @item.save y hacer que vuelva a mostrar la vista si se produce algún error.

Todavía no puedo determinar si esto es un error o una característica de Rails.Si alguien tiene alguna idea sobre el tema o mi solución, estaría muy contento de escucharlos.

+0

Solo para su información, consulte también este billete antiguo de Rails: https://rails.lighthouseapp.com/projects/8994/tickets/4254-assigning-nested-attributes-fails-for-new-object-when-id-is-specified –

Cuestiones relacionadas