1

私の現在の作業環境はRails2.3.8です(私の会社がRails 3に移行しなかったさまざまな理由)。AJAX呼び出しを介してマルチモデルフォームの要素を更新しようとしています-ユーザーが他のフィールドを選択または入力する方法に応じて、特定のドロップダウンを置き換えるという考えです。

以前は、フォームベースではないパーシャルを使用してこれを機能させることができました。現在の問題は、パーシャルがform_forとfields_forに基づいている場合に、選択ドロップダウンのAJAX更新を再現することです。

次のテキストの壁で申し訳ありません-私はそれを可能な限り削減しようとしました(コード自体は私のテストサイトで機能します)。

Outbreakコントローラーでフォームビルダー要素を生成し、これをカテゴリpartialに渡してincident_formの代わりにするにはどうすればよいですか?

どんなポインタも素晴らしいでしょう:D

モデル

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

ビュー

_形

<% 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

update_select_menusを呼び出した後、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

コントローラー

アウトブレイク

    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
4

1 に答える 1

1

http://www.treibstofff.de/2009/07/12/ruby-on-rails-23-nested-attributes-with-ajax-support/に基づいて回避策を見つけました

これはおそらくアウトブレイクヘルパー(アウトブレイクコントローラー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

アウトブレイクビュー(このパーシャルはインシデントに関連しているため、代わりにそのビューに表示される可能性があります)

    <% 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 %>

ActionView :: Helpers :: FormBuilderは、必須のfields_forフォームを生成するために使用されます-Webサイトの記事では、これについて詳しく説明しています。

結果のインデックスは、元のAJAX呼び出しによってコントローラーに渡すことができる@next_child_index変数によって設定されます(たとえば、@ next_child_index = 1の場合、結果のフォーム要素名はoutbreak [incidents_attributes] [1] [category_id])-この例ではこれを使用していません。将来、このフォームがこの最初のランスルーでアウトブレイクごとに複数の場所をサポートするようにしたいのですが、フォームは1つの場所(アウトブレイクごとのインシデント)のみを受け入れるためです。

_category_select.erb部分的(アウトブレイクビュー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)}"}) %>

with_strは、アウトブレイクIDが存在する場合は、それが存在する場合はオプションでアウトブレイクIDを渡し、フォームを生成するアウトブレイクレコードを検索します。そうでない場合は、新しいアウトブレイクと、インシデントや場所などの関連するネストされた属性を構築します。

これを行うには、特にFormHelperを使用し、オプションのwith文字列を介してOutbreakIDを渡す方法が適切である必要があります。

于 2010-11-23T11:05:33.470 に答える