Utilizzando accepts_nested_attributes_for su un join tabella con i propri attributi - righe duplicate
-
28-09-2019 - |
Domanda
Ho le seguenti tre modelli (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
I parametri dal modulo di sembrano essere ok
"focolaio" => { "Locations_attributes" => { "0" => { "lon" => "- 1,39", "toponimo" => "wetwe", "hpu_id" => "15", "Cap" => "1AA SO1", "region_id" => "10", "Indirizzo_1" => "", "città" => "Bargate", "Indirizzo_2" => "", "address_3" => "", "lat" => "50.89" }}, "incidents_attributes" => { "0" => { "subtype_id" => "7", "category_id" => "1", "dettaglio" => "", "subcategory_id" => "2"} } }
Ma quando l'epidemia è salvato 3 file vengono creati nella tabella Incidenti (la tabella join) e una singola riga nel focolaio e tavoli Posizione.
Le righe della tabella incidenti non sono completamente compilata dalle params come segue:
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
Questo deve essere dovuto alla sia il formato dei parametri o multiplo accepts_nested_attributes_for metodi -? Come posso avere solo una singola riga di essere inserito nella tabella Incidenti con tutte le informazioni parametri
Soluzione
La seconda volta finora in questa settimana ho risposto alla mia domanda ^^ che ti insegnarmi a fare uno sforzo maggiore nella prima di rinunciare e la pubblicazione in rete per aiuto,
Ancora dopo aver guardato la mia domanda iniziale non ho incluso informazioni sufficienti per rispondere in modo corretto - il problema (a parte la messa a punto dei modelli) è sceso al costruttore Outbreak nel controller Outbreak nuovo metodo,
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
Revised 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
Le modifiche ai tre modelli
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
Questo sembra funzionare bene - anche postato il creare l'azione e la forma principale
Altri suggerimenti
L'azione ha solo bisogno di creare i params annidati previste: scoppio (i modelli fanno il lavoro)
.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 epidemia è piuttosto lunga così ho tagliato verso il basso per le due sezioni citate (anche se non c'è probabilmente più attributi e campi qui che è necessario per avere un'idea).
Un esempio della id dell'elemento HTML per i campi nidificati possono essere trovate in fondo nella observe_field helper Javascript. Un post che ho fatto sugli aggiornamenti AJAX di parziali nested_attributes_for potrebbe anche essere utile AJAX di 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)" ) %>