我有以下三个模型(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
表单中的参数似乎没问题
“爆发”=&GT; { “locations_attributes”=&gt; {“0”=&gt; {“lon”=&gt;“ - 1.39”,“placename”=&gt;“wetwe”,“hpu_id”=&gt;“15”,“邮政编码”=&gt; ;“so1 1aa”,“region_id”=&gt;“10”,“address_1”=&gt;“”,“town”=&gt;“Bargate”,“address_2”=&gt;“”,“address_3”=&gt; “”,“lat”=&gt;“50.89”}},“incidents_attributes”=&gt; {“0”=&gt; {“subtype_id”=&gt;“7”,“category_id”=&gt;“1”,“ detail“=&gt;”“,”subcategory_id“=&gt;”2“}} }
但是,当保存爆发时,会在“事件”表(连接表)中创建3行,在“爆发”和“位置”表中创建一行。
事件表中的行未完全填充参数,如下所示:
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
这必须归因于参数的格式或多个accepts_nested_attributes_for方法 - 如何在Incidents表中输入一行并包含所有参数信息?
答案 0 :(得分:3)
本周第二次到目前为止,我已经回答了我自己的问题^^这将教会我在放弃并在网上发帖寻求帮助之前付出更多努力,
在查看我原来的问题之后,我没有提供足够的信息来正确回答 - 问题(除了模型的设置)是由爆发控制器新方法中的爆发构造函数,
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
修订了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
对三个模型的更改
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
这似乎工作正常 - 还发布了创建动作和主要表单
答案 1 :(得分:1)
创建操作只需要为以下内容提供的嵌套参数:爆发(模型可以完成工作)。
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
爆发形式很长,所以我把它简化为所提到的两个部分(虽然这里可能有更多属性和字段,但需要了解一下)。
嵌套字段的HTML元素id的示例可以在Javascript observe_field帮助器的底部找到。我在nested上更新nested_attributes_for partials的帖子可能也很有用AJAX update of 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)" ) %>