AJAX更新accepts_nested_attributes_for谐音的 [英] AJAX update of accepts_nested_attributes_for partials

查看:239
本文介绍了AJAX更新accepts_nested_attributes_for谐音的的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前的工作环境是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 | %>
< D​​IV 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆