6

Update: answered here.Rails 3: nested_form, collection_select, accepts_nested_attributes_for y fields_for

Hay muchas buenas preguntas y respuestas aquí y en el interweb sobre cómo obtener nested_form, collection_select, accepts_nested_attributes_for y fields_for para jugar muy bien juntas, pero todavía estoy perplejo. Gracias de antemano si me pueden ayudar.

Objetivo: Generar un nuevo registro ISBN. Un isbn puede tener muchos contribuyentes. Estoy utilizando con éxito el ryanb nested_form gem para producir dinámicamente nuevos campos de contribuyentes en un formulario, según sea necesario. Uno de estos campos usa un menú desplegable collection_select de todos los registros de nombre en Contributor. Cuando se crea el nuevo registro, los muchos identificadores de contribuyentes deben escribirse en la tabla de combinación (contribuyentes_informes).

he conseguido bits de este trabajo, pero sólo hasta el punto en que puedo guardar un único ID de contribuyente del nuevo registro en la tabla ISBN. Parece que no puedo escribir ningún dato en la tabla de unión.

que tengo tres modelos. Los colaboradores e Isbns tienen una relación de muchos a muchos, lo que he hecho usando has_many: through. Un isbn puede tener muchos contribuyentes, y un colaborador puede tener muchos isbns. Se unen a través de contribuidores_isbn.

isbn.rb

attr_accessible    :contributor_id 
    has_many      :contributors, :through => :contributors_isbns 
    has_many      :contributors_isbns 
    accepts_nested_attributes_for :contributors 
    accepts_nested_attributes_for :contributors_isbns 

contributor.rb

attr_accessible    :isbn_id 
    has_many      :contributors_isbns 
    has_many      :isbns, :through => :contributors_isbns 
    accepts_nested_attributes_for :isbns 

contributors_isbn.rb

class ContributorsIsbn 
    attr_accessible    :isbn_id, :contributor_id 
    belongs_to     :isbn 
    belongs_to     :contributor 
    accepts_nested_attributes_for :contributors 

En el controlador ISBN:

def new 
    @isbn = Isbn.new 
    @title = "Create new ISBN" 
    1.times {@isbn.contributors.build} 
    @isbn.contributors_isbns.build.build_contributor 
    end 

(obviamente no puedo decidirme sobre el que construir método a utilizar.)

En los ISBN new.html.erb vista:

<%= nested_form_for @isbn, :validate => false do |f| %> 
<h1>Create new ISBN</h1> 
<%= render 'shared/error_messages', :object => f.object %> 
<%= render 'fields', :f => f %> 
    <div class="actions"> 
    <%= f.submit "Create" %> 
    </div> 

<% end %> 

En los _fields parciales, una versión con una text_field muy sencillo:

<%= field_set_tag 'Contributor' do %> 
<%= f.link_to_add "Add Additional Contributor", :contributors %> 
<li> 
<%= f.label 'Contributor Sequence Number' %> 
<%= f.text_field :descriptivedetail_contributor_sequencenumber%> 
</li> 

<%= f.fields_for :contributors_isbns, :validate => false do |contrib| %> 
<li> 
<%= contrib.label :id, 'contributors_isbns id' %> 
<%= contrib.text_field :id %> 
</li> 
<% end %> 

<li> 
<%= f.label 'Contributor Role' %> 
<%= f.text_field :descriptivedetail_contributor_contributorrole %> 
</li> 

<% end %> 

Y aquí, una versión más elegante que no funciona bien:

<%= f.fields_for :contributors_isbns, :validate => false do |contributors| %> 
<li> 
<%= f.label :personnameinverted, 'Contributor Name' %> 
<%= f.collection_select(:contributor_id, Contributor.all, :id, :personnameinverted) %> 
</li> 
<% end %> 

Este código usa la respuesta de here. Ambos resultan en un error de 'bloque que falta" en la línea nested_form_for @isbn

Muchas gracias de nuevo por adelantado

Actualización:.. here es algo de información acerca de la gema nested_form que podría ser útil para mirar este tipo de problema. Y aquí hay una [publicación 2009 pero aún relevante] [4] en accept_nested_attributes_for.

Actualización 2: bueno, he aquí algo. He estado hurgando en una versión reducida de esto en dos modelos diferentes, no usando collection_select o has_many through, pero solo en una asociación simple belongs_to/has_many. El modelo padre es Contract y el modelo hijo es Istc. No pude crear un rec ord a través de la forma anidada. Sin embargo, después de buscar en la pila y buscar en Google el mensaje de error "Advertencia".atributos protegidos no se pueden asignar en masa" Me acaba de añadir a mi línea :istcs_attributes:attr_accessible y ahora se puede agregar registros. Un poco más importante que falta, y un caso de RTFM, ya que está justo allí en el readme joya. Voy a actualizar más tarde para ver si esto funciona en el has_many más complicado través de la asociación

actualización 4:. [Aquí] [5] es otro post útil sobre cómo tratar con un mensaje de error de registro nula

Update 5.: Desvío leve: cuando añadí dinámicamente un nuevo conjunto de campos al formulario, se creó uno de los registros secundarios. Duh: tenía el enlace "Agregar" dentro del área de formularios secundarios. Aquí está el antes:

<%= f.fields_for :istcs do |istc_form| %> 
<h4> Istc</h4> 
<%= istc_form.label "istc name" %> 
<%= istc_form.text_field :title_title_text %> 
<%= istc_form.link_to_remove "[-] Remove this istc"%> 
<%= f.link_to_add "[+] Add an istc", :istcs %> 
<% end %> 

Y aquí está el después:

<%= f.fields_for :istcs do |istc_form| %> 
<h4> Istc</h4> 
<%= istc_form.label "istc name" %> 
<%= istc_form.text_field :title_title_text %> 
<%= istc_form.link_to_remove "[-] Remove this istc"%> 
<% end %> 
<%= f.link_to_add "[+] Add an istc", :istcs %> 

Actualización 6, después de la respuesta:

Oh no. El collection_select no está funcionando. Se trata de agregar nuevos registros de contribuyentes, sin utilizar uno existente del modelo de contribuyente. Someone else tenía este problema también. ¿Algunas ideas?

Respuesta

3

Hurra! Aquí está el código que hace que todo esto funcione. Poco detallado pero no quería dejar nada fuera. Mis principales aprendizajes:

  • que necesita para hacer atributos attr_accessible en el modelo de los padres del niño

  • que necesita para hacer los identificadores primarios y secundarios attr_accessible en el modelo de tabla de unión

  • se hace es más fácil si construye al menos una instancia hija en el controlador principal.

modelo contributor.rb

class Contributor < ActiveRecord::Base 
    attr_accessible #nothing relevant 
    has_many :contributors_isbns 
    has_many :isbns, :through => :contributors_isbns 

modelo isbn.rb

class Isbn < ActiveRecord::Base 
    attr_accessible :contributors_attributes, :contributor_id, :istc_id #etc 
    belongs_to :istc 
    has_many :contributors, :through => :contributors_isbns 
    has_many :contributors_isbns 
    accepts_nested_attributes_for :contributors #if you omit this you get a missing block error 

modelo contributors_isbn

class ContributorsIsbn < ActiveRecord::Base 
    belongs_to :isbn 
    belongs_to :contributor 
    attr_accessible :isbn_id, :contributor_id 

controlador ISBN

def new 
    @isbn = Isbn.new 
    @title = "Create new ISBN" 
    1.times {@isbn.contributors.build} 
    end 

new.html.erb

<td class="main"> 
<%= nested_form_for @isbn, :validate => false do |f| %> 
<h1>Create new ISBN</h1> 
<%= render 'shared/error_messages', :object => f.object %> 
<%= render 'fields', :f => f %> 
    <div class="actions"> 
    <%= f.submit "Create" %> 
    </div> 

<% end %> 

_fields.html.erb

<%= field_set_tag 'Identifier Details' do %> 

<li> 
<%= f.label 'Title prefix' %> 
<%= f.text_field :descriptivedetail_titledetail_titleelement_titleprefix %> 
</li> 
<li> 
<%= f.label 'Title without prefix' %> 
<%= f.text_field :descriptivedetail_titledetail_titleelement_titlewithoutprefix %> 
</li> 
<li> 
<%= f.label 'ISTC' %> 
<%= f.collection_select(:istc_id, Istc.all, :id, :title_title_text, :prompt => true) %> 
</li> 

<% end %> 


<%= field_set_tag 'Contributor' do %> 
<li> 
<%= f.label 'Contributor Sequence Number' %> 
<%= f.text_field :descriptivedetail_contributor_sequencenumber%> 
</li> 

<%= f.fields_for :contributors, :validate => false do |contributor_form| %> 
<li> 
<%= contributor_form.label :personnameinverted, 'Contributor Name' %> 
<%= contributor_form.collection_select(:isbn_id, Contributor.all, :id, :personnameinverted) %> 
</li> 
<%= contributor_form.link_to_remove "[-] Remove this contributor"%> 
<% end %> 
<%= f.link_to_add "[+] Add a contributor", :contributors %> 


<li> 
<%= f.label 'Contributor Role' %> 
<%= f.text_field :descriptivedetail_contributor_contributorrole %> 
</li> 

<% end %> 
Cuestiones relacionadas