2010-09-23 14 views
6

Estoy trabajando en una forma desordenada que, entre otras cosas, tiene que gestionar una sección con dos niveles de anidación. Está casi funcionando, pero hay un inconveniente y lo único que puedo ver que es diferente de otras formas profundamente anidadas que funcionan es que hay una relación belongs_to en lugar de has_many. Estos son los modelos:Formas de rieles profundamente anidadas usando belong_to no funciona?

Event 
    has_many :company_events, :dependent => :destroy 
    accepts_nested_attributes_for :company_events 

CompanyEvent 
    belongs_to :company 
    accepts_nested_attributes_for :company, :update_only => true 
    belongs_to :event 
    belongs_to :event_type 

Company 
    has_many :company_events 
    has_many :events, :through => :company_events 

lo que es una relación de muchos a muchos bastante estándar a través de una tabla de enlace, company_events. El formulario en cuestión está creando/editando un evento, con un botón dinámico de "Agregar compañía" de Javascript, todo basado en el screencast de Ryan Bates y en el repositorio de GitHub.

La forma principal:

<table id="companies"> 
    <tr><th>Company Name</th></tr> 
    <% f.fields_for :company_events do |builder| %> 
    <%= render 'company_event_fields', :f => builder, :f_o => nil %> 
    <% end -%> 
</table> 
<p><br/><%= link_to_add_fields "Add Company", f, :company_events, "events" %></p> 

Y el formulario incluido es la siguiente. Una cosa importante a tener en cuenta es que la identificación de la compañía se establece a través de una actualización de Javascript, que no incluiré aquí porque es larga. Básicamente, el usuario comienza a escribir un nombre, se muestra una lista de autocompletar y al hacer clic en el nombre se establece el nombre de la empresa y el ID en el formulario.

<tr class="company_event_fields"> 
    <td> 
    <% f.fields_for(:company) do |company_form| -%> 
     <%= company_form.text_field :name, :size => 80 %> 
     <%= company_form.hidden_field :id %> 
    <% end -%> 
    </td> 
    <td> 
    <%= f.hidden_field :_destroy %> 
    <%= link_to_function "remove", "remove_co_fields(this)" %> 
    </td> 
</tr> 

Cuando actualizo un registro existente, todo funciona bien. Cuando trato de guardar el formulario con un registro recién creado, sin embargo, me sale:

ActiveRecord::RecordNotFound in EventsController#update 

Couldn't find Company with ID=12345 for CompanyEvent with ID= 

Con la StackTrace:

/Library/Ruby/Gems/1.8/gems/activerecord-2.3.8/lib/active_record/nested_attributes.rb:401:in `raise_nested_attributes_record_not_found' 
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.8/lib/active_record/nested_attributes.rb:289:in `assign_nested_attributes_for_one_to_one_association' 
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.8/lib/active_record/nested_attributes.rb:244:in `company_attributes=' 
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.8/lib/active_record/base.rb:2906:in `send' 

He mirado a través del código en nested_attributes, y correr a través con un depurador Lo que está sucediendo parece ser que, debido a que hay un Company.id, ActiveRecord está asumiendo que ya hay una entrada, pero luego, por supuesto, no encuentra ninguna. Esto parece muy extraño, ya que obviamente necesitaría pasar una identificación para crear una nueva entrada de CompanyEvent. Entonces, supongo que me estoy perdiendo algo.

Los ejemplos que he encontrado que funcionan parecen anidados utilizando has_many relaciones hasta el final, mientras que en este caso es un belongs_to, y me pregunto si esa es la raíz del problema. Cualquier idea sería muy apreciada ...

Respuesta

4

Me encontré con el mismo problema, parece que los rieles no admiten el uso de modelos anidados como este: no se puede guardar un nuevo objeto con un modelo anidado que existe, por ejemplo, imaginar esta situación:

class Monkey < ActiveRecord::Base 
end 
class Banana < ActiveRecord::Base 
    belongs_to :monkey 
    accepts_nested_attributes_for :monkey 
end 

esto no trabajará si se intenta en la consola:

banana = Banana.create! 
monkey = Monkey.new 
monkey.attributes = {:banana_attributes => { :id => banana.id}} 

pero es facil de solucionar este problema, en su forma que no es necesario para establecer los atributos anidados si su plátano ya es persistente, solo necesita tener un campo oculto en el forma de mono con banana_id, que dará como resultado algo así como:

monkey.attributes = {:banana_id => banana.id} 

Y eso va a ahorrar muy bien.

+0

Yo no probar el código, pero si usted tiene accepts_nested_attributes_for: mono, no debería ser tu ejemplo banana.attributes = {...}: monkey_attributes? monkey.attributes = {: banana_attributes ...} no parece funcionar. –

13

Aquí hay otra solución posible que he publicado en una pregunta similar: https://stackoverflow.com/a/12064875/47185

Algo como esto ...

accepts_nested_attributes_for :company 
    def company_attributes=(attributes) 
    if attributes['id'].present? 
     self.company = Company.find(attributes['id']) 
    end 
    super 
    end 
Cuestiones relacionadas