AJAX更新accepts_nested_attributes_for谐音的 [英] AJAX update of accepts_nested_attributes_for partials
问题描述
我目前的工作环境是Rails的 2.3.8 (各种原因,我公司并没有转移到Rails 3中)。 我试图更新一个多模式的形式要素,通过AJAX调用 - 的想法是更换某些下拉菜单取决于用户如何选择或填写其他领域
我有previously管理使用非基于表单的谐音得到这个工作 - 这个问题我现在已经是重现选择下拉菜单的AJAX更新时,谐音是根据各地的form_for和fields_for
对不起,文字的下面壁 - 我试着剪下来尽可能地(在code本身确实在我的测试现场工作)
。如何生成的爆发控制器表单生成器元素,然后把它传递给类部分采取incident_form的地方?
任何指针将是巨大的:D
模式
类疫情<的ActiveRecord :: Base的
的has_many:事故,:依赖=> :破坏
的has_many:地点:通过=> :事件
accepts_nested_attributes_for:地点:allow_destroy =>如此,:reject_if => :all_blank
accepts_nested_attributes_for:事故,:allow_destroy =>如此,:reject_if => :all_blank
结束
类事件与LT;的ActiveRecord :: Base的
belongs_to的:爆发
belongs_to的:位置
belongs_to的:类
belongs_to的:子类别
belongs_to的:亚型
结束
一流的位置和LT;的ActiveRecord :: Base的
的has_many:事故,:依赖=> :破坏
的has_many:爆发:thorugh =>事故
结束
浏览
_form
<%的form_for(@outbreak,:HTML => {:多部分=>真})办|形式| %>
<%=渲染:部分=> outbreak_type_select',:当地人=> {:outbreak_types => @outbreak_types,:F =>形式}%GT;
<%form.fields_for:事件做| incident_form | %>
<%=渲染:部分=> category_select',:当地人=> {:类=> @categories,:incident_form => incident_form}%GT;
<%=渲染:部分=> subcategory_select',:当地人=> {:子类=> @subcategories,:incident_form => incident_form}%GT;
<%结束%GT;
<%结束%GT;
_outbreak_type_select
<%with_str ='outbreak_type ='+价值%>
<%@如果outbreak.id%GT;
<%with_str<< +和ID ='+#{outbreak.id}%>
<%结束%GT;
<%= f.collection_select(:outbreak_type,@outbreak_types,:property_value,:property_value,{},{:的onchange =>中#{remote_function(:URL => {:动作=>中update_select_menus}, :与=> with_str)})%>
_category_select
要求update_select_menus如何生成incident_form后
<%= incident_form.collection_select(:CATEGORY_ID,@categories,:ID,:姓名,{:提示=>中选择一个类别},{:的onchange =&GT ;#{remote_function(:URL => {:动作=>中update_subcategory}:与=>中CATEGORY_ID ='+价值)})%>
RJS
开始
page.replace_htmloutbreak_transmission_div',:部分=> 暴发/ transmission_mode_select',:当地人=> {:transmission_modes => @transmission_modes}
拯救
page.insert_html:底部,'ajax_error','&其中p为H.;错误::传输模式更新选择&所述; / P>'
page.showajax_error
结束
开始
page.replace_htmlincident_category_select',:部分=> 暴发/ category_select',:当地人=> {:类=> @categories}
拯救
page.insert_html:底部,ajax_error','< P>错误::事件类别更新选择< / P>
page.showajax_error
结束
控制器
爆发
高清新
@outbreak = Outbreak.new
@ outbreak.incidents.build
@ outbreak.locations.build
#just的下拉菜单中的内容
@categories = Category.find(:所有,:条件=> {:outbreak_type =>中食源性}:为了=>中outbreak_type ASC)
@subcategories = Subcategory.find(:所有,:为了=>中CATEGORY_ID ASC)
结束
高清update_select_menus
@outbreak_type = PARAMS [:outbreak_type] .strip
如果PARAMS [:ID]
@outbreak = Outbreak.find(PARAMS [:ID])
其他
@outbreak = Outbreak.new
@ outbreak.incidents.build
@ outbreak.locations.build
结束
如果@outbreak_type ==食源性
ob_type_query =暴发:TRANSMISSION_MODE:<< @outbreak_type
@transmission_modes = Property.find(:所有,:条件=> {:字段=> ob_type_query})
ob_type_query =调查:类别:<< @outbreak_type
@sample_types = Property.find(:所有,:条件=> {:字段=> ob_type_query})
@categories = Category.find(:所有,:条件=> {:outbreak_type =>中食源性})
@subcategories = Subcategory.find(:所有,:条件=> {:CATEGORY_ID => @ categories.first.id})
@subtypes = Subtype.find(:所有,:条件=> {:subcategory_id => @ subcategories.first.id})
ELSIF @outbreak_type ==非食源性
ob_type_query =暴发:TRANSMISSION_MODE:<< @outbreak_type
@transmission_modes = Property.find(:所有,:条件=> {:字段=> ob_type_query})
ob_type_query =调查:类别:<< @outbreak_type
@sample_types = Property.find(:所有,:条件=> {:字段=> ob_type_query})
@categories = Category.find(:所有,:条件=> {:outbreak_type =>中NON-食源性})
@subcategories = Subcategory.find(:所有,:条件=> {:CATEGORY_ID => @ categories.first.id})
@subtypes = Subtype.find(:所有,:条件=> {:subcategory_id => @ subcategories.first.id})
结束
respond_to代码做|格式|
的format.html
format.js
结束
结束
发现周围的工作基础上的http://www.treibstofff.de/2009/07/12/ruby-on-rails-23-nested-attributes-with-ajax-support/
这也许应该在爆发帮手(在爆发控制器ATM)
高清update_select_menus
@outbreak_type = PARAMS [:outbreak_type] .strip
#next_child_index将只如果使用
@next_child_index? PARAMS [:next_child_index]:0
如果PARAMS [:ID]
@outbreak = Outbreak.find(PARAMS [:ID])
其他
@outbreak = Outbreak.new
@ outbreak.risks.build
@ outbreak.incidents.build
@ outbreak.locations.build
结束
如果@outbreak_type ==食源性
ob_type_query =暴发:TRANSMISSION_MODE:<< @outbreak_type
@transmission_modes = Property.find(:所有,:条件=> {:字段=> ob_type_query})
ob_type_query =调查:类别:<< @outbreak_type
@sample_types = Property.find(:所有,:条件=> {:字段=> ob_type_query})
@categories = Category.find(:所有,:条件=> {:outbreak_type =>中食源性})
@subcategories = Subcategory.find(:所有,:条件=> {:CATEGORY_ID => @ categories.first.id})
@subtypes = Subtype.find(:所有,:条件=> {:subcategory_id => @ subcategories.first.id})
ELSIF @outbreak_type ==非食源性
ob_type_query =暴发:TRANSMISSION_MODE:<< @outbreak_type
@transmission_modes = Property.find(:所有,:条件=> {:字段=> ob_type_query})
ob_type_query =调查:类别:<< @outbreak_type
@sample_types = Property.find(:所有,:条件=> {:字段=> ob_type_query})
@categories = Category.find(:所有,:条件=> {:outbreak_type =>中NON-食源性})
@subcategories = Subcategory.find(:所有,:条件=> {:CATEGORY_ID => @ categories.first.id})
@subtypes = Subtype.find(:所有,:条件=> {:subcategory_id => @ subcategories.first.id})
结束
@pathogen_types = Property.find(:所有,:条件=> {:字段=>中致病菌:类别})
@outbreak_types = Property.find(:所有,:条件=> {:字段=>中暴发:OUTBREAK_TYPE})
渲染:更新办|首页|
page.replaceoutbreak_transmission_div',:部分=> transmission_mode_select_update
page.replaceincident_category_select',:部分=> incident_category_select_update
page.replaceincident_subcategory_select',:部分=> incident_subcategory_select_update
page.replaceincident_subtype_select',:部分=> incident_subtype_select_update
结束
结束
在爆发视图(虽然因为这部分涉及到事件它应该去的视图,而不是)
<%而ActionView ::助手:: FormBuilder.new。(:爆发,@outbreak,@Template,{},PROC {})fields_for:事故,{:CHILD_INDEX = > @next_child_index}做| this_form | %>
< DIV ID =incident_category_select>
<%=渲染:部分=> category_select',:当地人=> {:incident_form => this_form}%GT;
< / DIV>
<%结束%GT;
的的ActionView ::助手:: FormBuilder用于产生所需fields_for形式 - 该网站文章经过此更详细
将所得的指数是通过其可以被传递给控制器由原始AJAX调用(例如@next_child_index = 1 @next_child_index变量设置,然后将所得的表格元件名称将是的爆发[incidents_attributes] [1 ] [CATEGORY_ID] ) - 我没有用过这个在这个例子中,因为虽然在未来,我希望表单支持每个爆发多个位置的初始运行通过它只是接受一个位置 - 事件每个爆发。
_category_select.erb部分(在爆发查看ATM)
<%with_str ='CATEGORY_ID ='+价值%>
<%@如果outbreak.id%GT;
<%with_str<< +和ID ='+ #{@outbreak.id}%>
<%结束%GT;
<%= incident_form.collection_select(:CATEGORY_ID,@categories,:ID,:姓名,{:提示=>中选择一个类别},{:的onchange =>中#{remote_function(:URL => { :行动=>中update_subcategory}:与=> with_str)})%>
该with_str只是有选择地通过爆发ID(如果存在)到控制器找到爆发的记录产生的形式,如果没有建立一个新的爆发和相关的嵌套的属性,如事件和位置。
在必须这样做的简洁的方式 - 尤其是表单助手,并通过可选的字符串传递爆发ID
My current working environment is Rails 2.3.8 (various reasons why my company hasn't moved to Rails 3). I'm trying to update elements of a multi-model form via AJAX calls - the idea being to replace certain dropdowns depending on how the user selects or fills in other fields.
I have previously managed to get this working by using non-form based partials - the problem I have now is to reproduce the AJAX updating of the select dropdowns when the partials are based around form_for and fields_for.
Sorry for the following wall of text - i've tried to cut it down as much as possible (the code itself does work on my test site).
How do I generate the form builder elements in the Outbreak controller and then pass this to the category partial to take the place of incident_form?
Any pointers would be great :D
Models
class Outbreak < ActiveRecord::Base
has_many :incidents, :dependent => :destroy
has_many :locations, :through => :incidents
accepts_nested_attributes_for :locations, :allow_destroy => true, :reject_if => :all_blank
accepts_nested_attributes_for :incidents, :allow_destroy => true, :reject_if => :all_blank
end
class Incident < ActiveRecord::Base
belongs_to :outbreak
belongs_to :location
belongs_to :category
belongs_to :subcategory
belongs_to :subtype
end
class Location < ActiveRecord::Base
has_many :incidents, :dependent => :destroy
has_many :outbreaks, :thorugh => incidents
end
Views
_form
<% form_for(@outbreak, :html => {:multipart => true}) do |form| %>
<%= render :partial => 'outbreak_type_select', :locals => {:outbreak_types => @outbreak_types, :f => form } %>
<% form.fields_for :incidents do |incident_form| %>
<%= render :partial => 'category_select', :locals => {:categories => @categories, :incident_form => incident_form} %>
<%= render :partial => 'subcategory_select', :locals => { :subcategories => @subcategories, :incident_form => incident_form } %>
<% end %>
<% end %>
_outbreak_type_select
<% with_str = "'outbreak_type=' + value " %>
<% if @outbreak.id %>
<% with_str << "+ '&id=' + #{outbreak.id}" %>
<% end %>
<%= f.collection_select(:outbreak_type, @outbreak_types, :property_value, :property_value, {}, {:onchange => "#{remote_function(:url => { :action => "update_select_menus"}, :with => with_str)}"} ) %>
_category_select
After calling update_select_menus how to generate the incident_form
<%= incident_form.collection_select( :category_id, @categories, :id, :name, {:prompt => "Select a category"}, {:onchange => "#{remote_function(:url => { :action => "update_subcategory"}, :with => "'category_id='+value")}"}) %>
RJS
begin
page.replace_html 'outbreak_transmission_div', :partial => 'outbreaks/transmission_mode_select', :locals => {:transmission_modes => @transmission_modes }
rescue
page.insert_html :bottom, 'ajax_error', '<p>Error :: transmission modes update select</p>'
page.show 'ajax_error'
end
begin
page.replace_html 'incident_category_select', :partial => 'outbreaks/category_select', :locals => { :categories => @categories }
rescue
page.insert_html :bottom, 'ajax_error', '<p>Error :: incident category update select</p>'
page.show 'ajax_error'
end
Controllers
Outbreak
def new
@outbreak = Outbreak.new
@outbreak.incidents.build
@outbreak.locations.build
#just the contents for the dropdowns
@categories = Category.find(:all, :conditions => {:outbreak_type => "FOODBORNE"}, :order => "outbreak_type ASC")
@subcategories = Subcategory.find(:all, :order => "category_id ASC")
end
def update_select_menus
@outbreak_type = params[:outbreak_type].strip
if params[:id]
@outbreak = Outbreak.find(params[:id])
else
@outbreak = Outbreak.new
@outbreak.incidents.build
@outbreak.locations.build
end
if @outbreak_type == "FOODBORNE"
ob_type_query = "OUTBREAKS:TRANSMISSION_MODE:" << @outbreak_type
@transmission_modes = Property.find(:all, :conditions => {:field => ob_type_query})
ob_type_query = "INVESTIGATIONS:CATEGORY:" << @outbreak_type
@sample_types = Property.find(:all, :conditions => {:field => ob_type_query})
@categories = Category.find(:all, :conditions => { :outbreak_type => "FOODBORNE"})
@subcategories = Subcategory.find(:all, :conditions => { :category_id => @categories.first.id})
@subtypes = Subtype.find(:all, :conditions => { :subcategory_id => @subcategories.first.id})
elsif @outbreak_type == "NON-FOODBORNE"
ob_type_query = "OUTBREAKS:TRANSMISSION_MODE:" << @outbreak_type
@transmission_modes = Property.find(:all, :conditions => {:field => ob_type_query})
ob_type_query = "INVESTIGATIONS:CATEGORY:" << @outbreak_type
@sample_types = Property.find(:all, :conditions => {:field => ob_type_query})
@categories = Category.find(:all, :conditions => { :outbreak_type => "NON-FOODBORNE"})
@subcategories = Subcategory.find(:all, :conditions => { :category_id => @categories.first.id})
@subtypes = Subtype.find(:all, :conditions => { :subcategory_id => @subcategories.first.id})
end
respond_to do |format|
format.html
format.js
end
end
Found a work around based on http://www.treibstofff.de/2009/07/12/ruby-on-rails-23-nested-attributes-with-ajax-support/
This should probably go in Outbreak helper (in Outbreak controller atm)
def update_select_menus
@outbreak_type = params[:outbreak_type].strip
#next_child_index will only be used if
@next_child_index ? params[:next_child_index] : 0
if params[:id]
@outbreak = Outbreak.find(params[:id])
else
@outbreak = Outbreak.new
@outbreak.risks.build
@outbreak.incidents.build
@outbreak.locations.build
end
if @outbreak_type == "FOODBORNE"
ob_type_query = "OUTBREAKS:TRANSMISSION_MODE:" << @outbreak_type
@transmission_modes = Property.find(:all, :conditions => {:field => ob_type_query})
ob_type_query = "INVESTIGATIONS:CATEGORY:" << @outbreak_type
@sample_types = Property.find(:all, :conditions => {:field => ob_type_query})
@categories = Category.find(:all, :conditions => { :outbreak_type => "FOODBORNE"})
@subcategories = Subcategory.find(:all, :conditions => { :category_id => @categories.first.id})
@subtypes = Subtype.find(:all, :conditions => { :subcategory_id => @subcategories.first.id})
elsif @outbreak_type == "NON-FOODBORNE"
ob_type_query = "OUTBREAKS:TRANSMISSION_MODE:" << @outbreak_type
@transmission_modes = Property.find(:all, :conditions => {:field => ob_type_query})
ob_type_query = "INVESTIGATIONS:CATEGORY:" << @outbreak_type
@sample_types = Property.find(:all, :conditions => {:field => ob_type_query})
@categories = Category.find(:all, :conditions => { :outbreak_type => "NON-FOODBORNE"})
@subcategories = Subcategory.find(:all, :conditions => { :category_id => @categories.first.id})
@subtypes = Subtype.find(:all, :conditions => { :subcategory_id => @subcategories.first.id})
end
@pathogen_types = Property.find(:all, :conditions => {:field => "PATHOGENS:CATEGORY"})
@outbreak_types = Property.find(:all, :conditions => {:field => "OUTBREAKS:OUTBREAK_TYPE"} )
render :update do |page|
page.replace 'outbreak_transmission_div', :partial => 'transmission_mode_select_update'
page.replace 'incident_category_select', :partial => 'incident_category_select_update'
page.replace 'incident_subcategory_select', :partial => 'incident_subcategory_select_update'
page.replace 'incident_subtype_select', :partial => 'incident_subtype_select_update'
end
end
In the Outbreak view (although since this partial is related to Incident it should probably go in that view instead)
<% ActionView::Helpers::FormBuilder.new(:outbreak, @outbreak, @template, {}, proc{}).fields_for :incidents,{:child_index => @next_child_index} do |this_form| %>
<div id="incident_category_select">
<%= render :partial => 'category_select', :locals => {:incident_form => this_form } %>
</div>
<% end %>
The ActionView::Helpers::FormBuilder is used to produce the required fields_for form - The website article goes through this in more detail.
The resulting index is set by the @next_child_index variable which can be passed to the controller by the original AJAX call (for example @next_child_index = 1, then the resulting form element name will be outbreak [incidents_attributes] [1] [category_id] ) - I haven't used this in this example because although in future I want the form to support more than one location per Outbreak for this initial run-through it will just accept a single Location - Incident per Outbreak.
_category_select.erb partial (in Outbreak view atm)
<% with_str = "'category_id=' + value " %>
<% if @outbreak.id %>
<% with_str << "+ '&id=' + #{@outbreak.id}" %>
<% end %>
<%= incident_form.collection_select( :category_id, @categories, :id, :name, {:prompt => "Select a category"}, {:onchange => "#{remote_function(:url => { :action => "update_subcategory"}, :with => with_str)}"}) %>
The with_str is just to optionally pass the Outbreak id if it exists to the controller to find the Outbreak record to produce the form and if not to build a new Outbreak and associated nested attributes like Incidents and Locations.
The must be neater ways of doing this - especially the FormHelper and passing the Outbreak id via the optional with string.
这篇关于AJAX更新accepts_nested_attributes_for谐音的的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!