Usando accepts_nested_attributes_for en una tabla de unión con sus propios atributos - filas duplicadas

StackOverflow https://stackoverflow.com/questions/4279028

Pregunta

Tengo los tres modelos siguientes (Rails 2.3.8)

    class Outbreak < ActiveRecord::Base
        has_many :incidents, :dependent => :destroy
        has_many :locations, :through => :incidents

        accepts_nested_attributes_for :incidents, :allow_destroy => true
        accepts_nested_attributes_for :locations, :allow_destroy => true, :reject_if => proc { |attrs| attrs.all? { |k, v| v.blank? } }

    end

   class Incident < ActiveRecord::Base
        belongs_to :outbreak
        belongs_to :location
   end


   class Location < ActiveRecord::Base
 has_many :incidents
 has_many :outbreaks, :through => :incidents

     accepts_nested_attributes_for :incidents, :allow_destroy => true

   end

Los parámetros de la forma parecen estar bien

"brote" => { "Locations_attributes" => { "0" => { "lon" => "- 1.39", "placename" => "wetwe", "hpu_id" => "15", "código postal" => "1 bis bis SO1", "REGION_ID" => "10", "address_1" => "", "ciudad" => "Bargate", "address_2" => "", "address_3" => "", "lat" => "50.89" }}, "incidents_attributes" => { "0" => { "subtype_id" => "7", "category_id" => "1", "detalle" => "", "subcategory_id" => "2"} } }

Sin embargo, cuando el brote se guarda 3 filas se crean en la tabla Incidentes (la tabla de unión) y una sola fila en el brote y tablas Ubicación.

Las filas de la tabla incidentes no se rellenan completamente de los params como sigue:

id outbreak_id location_id category_id subcategory_id subtype_id detail  created_at    updated_at 

 57 23   NULL     1       2           7                          2010-11-25 14:45:18.385905  2010-11-25 14:45:18.385905 
 58 23   27         NULL       NULL        NULL    NULL           2010-11-25 14:45:18.39828  2010-11-25 14:45:18.39828 
 59 23   27         NULL         NULL     NULL      NULL           2010-11-25 14:45:18.403051  2010-11-25 14:45:18.403051 

Esto debe ser debido a la ya sea el formato de los parámetros o los múltiples métodos accepts_nested_attributes_for -? ¿Cómo tengo una sola fila que se está introducida en la tabla de incidentes con toda la información de parámetros

¿Fue útil?

Solución

La segunda vez en lo que va de esta semana he respondido a mi propia pregunta ^^ que me enseñará a poner más esfuerzo en antes de abandonar y publicación en la red en busca de ayuda,

Aún después de mirar en mi pregunta original no he incluido información suficiente para responder de forma adecuada - el problema (aparte de la puesta en marcha de los modelos) se redujo al constructor del brote en el controlador brote nuevo método,

Original Outbreaks_controller

def new

    @outbreak = Outbreak.new
    @outbreak.risks.build
    //links locations directly to Outbreak instead of through Incidents
    @outbreak.locations.build
    @outbreak.incidents.build

    respond_to do |format|
      format.html # new.html.erb
      format.xml  { render :xml => @outbreak }
    end
end

Revisado Outbreaks_controller

def new

    @outbreak = Outbreak.new
    @outbreak.risks.build
    //builds Incidents then a Location through that incident
    @outbreak.incidents.build.build_location

    respond_to do |format|
      format.html # new.html.erb
      format.xml  { render :xml => @outbreak }
    end
end

Los cambios en los tres modelos

    class Outbreak < ActiveRecord::Base
        has_many :incidents, :dependent => :destroy
        has_many :locations, :through => :incidents

        accepts_nested_attributes_for :incidents, :allow_destroy => true


    end

   class Incident < ActiveRecord::Base
        belongs_to :outbreak
        belongs_to :location

        accepts_nested_attributes_for :location, :allow_destroy => true
   end


   class Location < ActiveRecord::Base
       has_many :incidents
       has_many :outbreaks, :through => :incidents

   end

Esto parece bien el trabajo - también publicó la acción y crear forma principal

Otros consejos

La acción de crear sólo necesita los parametros anidados previstos: brote (los modelos de hacer el trabajo)

.
def create

    @outbreak = Outbreak.new(params[:outbreak])
    @outbreak.user_id = current_user.id

        respond_to do |format|
     if @outbreak.save
        flash[:notice] = 'Outbreak was successfully created.'
        format.html { redirect_to(@outbreak) }
        format.xml  { render :xml => @outbreak, :status => :created, :location => @outbreak }
      else
        format.html { render :action => "new" }
        format.xml  { render :xml => @outbreak.errors, :status => :unprocessable_entity }
      end
    end
end

La forma de brote es bastante largo corte por lo que he abajo a las dos secciones mencionadas (aunque es probable que haya más atributos y campos aquí que es necesario tener una idea).

Un ejemplo de la Identificación del elemento HTML de los campos anidados se puede encontrar en la parte inferior en el ayudante observe_field Javascript. Un post que hice sobre las actualizaciones parciales de AJAX nested_attributes_for también podría ser útil AJAX de accepts_nested_attributes_for

    <% form_for(@outbreak, :html => {:multipart => true}) do |form| %>
    <%= form.error_messages %>
    <div id="tabs">
        <ul>

            <li ><a href="#tabs_b">Outbreak</a></li>
            <li ><a href="#tabs_c">Location</a></li>

        </ul>   


            <div id="tabs_b">
                <fieldset id="b" class="form_div">
                    <legend>Outbreak</legend>

                    <fieldset>
                        <legend>References</legend>
                      <div class="left_form">
                        <%= form.label :user_reference %>
                      </div>
                      <div class="right_form">
                        <%= form.text_field :user_reference %>
                      </div>
                      <div style="clear:both;"></div>

                    </fieldset>

                </fieldset>
            </div>
            <div id="tabs_c">
                <fieldset id="c" class="form_div" >

                    <legend>Location</legend>
                      <div id="location_error"></div>
                            <fieldset>
                            <legend>Setting</legend>
                <% form.fields_for :incidents do |incident_form| %>

                                  <div class="left_form">
                                    <%= incident_form.label :category_id %>
                                  </div>

                                  <div class="right_form">
                                    <div id="incident_category_select">
                                    <%= render :partial => 'category_select', :locals => {:categories => @categories, :incident_form => incident_form} %>
                                    </div>
                                  </div>
                                  <div style="clear:both;"></div>

                                  <div class="left_form">
                                    <%= incident_form.label :subcategory_id %>
                                  </div>
                                  <div class="right_form">
                                    <div id="incident_subcategory_select">
                                    <%= render :partial => 'subcategory_select', :locals => { :subcategories => @subcategories, :incident_form => incident_form } %>
                                    </div>
                                  </div>
                                  <div style="clear:both;"></div>
                                  <div class="left_form">
                                    <%= incident_form.label :subtype_id %>
                                  </div>
                                  <div class="right_form">
                                    <div id="incident_subtype_select">
                                    <%= render :partial => 'subtype_select',  :locals => { :subtypes => @subtypes, :incident_form => incident_form } %>
                                    </div>
                                  </div>
                                  <div style="clear:both;"></div>
                                  <div id="cuisine_div">
                                    <% if @outbreak.outbreak_type == "FOODBORNE" %>
                                        <div class="left_form">
                                            <%= label :incident, :cuisine_id %>
                                        </div>
                                        <div class="right_form">
                                            <% cuisine_select = (@incident != nil ? @incident.cuisine_id.to_i : '') %>
                                            <%= incident_form.select( :cuisine_id, "<option value='' >Please select</option>" + options_from_collection_for_select(@cuisines, :id, :name, cuisine_select)) %>
                                        </div>
                                    <% end %>

                                  </div>
                                  <div style="clear:both;"></div>
                                  <div class="left_form">
                                    <%= incident_form.label :detail %>
                                  </div>
                                  <div class="right_form">
                                    <%= incident_form.text_field :detail %>
                                  </div>


                        </fieldset>
                        <fieldset>
                            <legend>Details</legend>
                            <%  incident_form.fields_for :location do |location_form| %>
                                  <div style="clear:both;"></div>
                                   <div class="left_form">
                                    <%= location_form.label :placename %>
                                  </div>
                                  <div class="right_form">
                                    <%= location_form.text_field :placename %>
                                  </div> 
                                  <div style="clear:both;"></div>
                                  <div class="left_form">
                                    <%= location_form.label :address_1 %>
                                  </div>
                                  <div class="right_form">
                                    <%= location_form.text_field :address_1 %>
                                  </div>
                                  <div style="clear:both;"></div>
                                  <div class="left_form">
                                    <%= location_form.label :address_2 %>
                                  </div>
                                  <div class="right_form">
                                    <%= location_form.text_field :address_2 %>
                                  </div>
                                  <div style="clear:both;"></div>
                                  <div class="left_form">
                                    <%= location_form.label :address_3 %>
                                  </div>
                                  <div class="right_form">
                                    <%= location_form.text_field :address_3 %>
                                  </div> 
                                  <div style="clear:both;"></div>
                                  <div class="left_form">
                                    <%= location_form.label :town %>
                                  </div>
                                  <div class="right_form">
                                    <%= location_form.text_field :town %>
                                  </div>
                                  <div style="clear:both;"></div>
                                  <div class="left_form">
                                    <%= location_form.label :postcode %>
                                  </div>
                                  <div class="right_form">
                                    <%= location_form.text_field :postcode %>
                                  </div>
                                  <div style="clear:both;"></div>        
                                  <div class="left_form">
                                    <%= location_form.label :region_id %>
                                  </div>
                                  <div class="right_form" >
                                        <% region_select = (@location != nil ? @location.region_id.to_i : '') %>
                                    <%= location_form.select(:region_id, "<option value=''>Select a region</option>" + options_from_collection_for_select(@regions, :id, :name, region_select)) %>
                                  </div>
                                  <div style="clear:both;"></div>
                                  <div class="left_form">
                                    <%= location_form.label :hpu_id %>
                                  </div>
                                  <div class="right_form" >
                                    <% hpu_select = (@location != nil ? @location.hpu_id.to_i : '') %>
                                    <%= location_form.select(:hpu_id, "<option value=''>Select a HPU</option>" + options_from_collection_for_select(@hpus, :id, :name, hpu_select)) %>
                                  </div>
                                  <div style="clear:both;"></div>

                                <%= location_form.hidden_field :lon, :value => '' %>
                                <%= location_form.hidden_field :lat, :value => '' %>
                                <%= hidden_field_tag :postcode_error, :value => '0' %>
                                <% end %>
                          </fieldset>


                    <% end %>       

                </fieldset>

            </div>


    </div>
    <% end %>

    <div style="clear: both; margin: 10px;"></div>
    <%= observe_field(:outbreak_incidents_attributes_0_location_attributes_postcode, 
              :url => { :controller => :locations, :action => :find_lonlat },
              :on => "onchange",
              :loading => "Element.show('loader')",
              :success => "Element.hide('loader')",
              :with => "'postcode=' + encodeURIComponent($('outbreak_incidents_attributes_0_location_attributes_postcode').value)" ) %>
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top