3

動作中のアプリをRails2.3からRails4.0に更新(およびリファクタリング)しています。このアプリには、「スマートグループ」と呼ばれる機能が含まれています。スマートグループは、保存して再利用して一連の「人」レコードを見つけることができる検索クエリを構築します。

スマートグループhas_manyスマートグループルールと各スマートグループルールは、0個以上の演算子を持つプロパティに属しています。

スマートグループを作成するフォームは、スマートグループルールの追加も処理します。ルールのプロパティを選択したら、フォームを更新して、選択したプロパティに関連付けられている演算子と、ルールの値を入力するためのフィールドを表示する必要があります。

問題は、選択したプロパティの演算子を表示するために、プロパティを選択したときにフォームを動的に更新する必要があることです。これは、Rails4.0では理解できない部分です。

class SmartGroup < ActiveRecord::Base
  has_many :rules, :class_name => "SmartGroupRule", :foreign_key => "smart_group_id"

  accepts_nested_attributes_for :rules, reject_if: :all_blank, allow_destroy: true
end

class SmartGroupRule < ActiveRecord::Base
  belongs_to :smart_group
  belongs_to :smart_group_property
  belongs_to :operator 
end

class SmartGroupProperty < ActiveRecord::Base
  has_many :smart_group_rules
  has_many :property_operators
  has_many :operators, through: :property_operators  
end

class Operator < ActiveRecord::Base
  has_many :property_operators
  has_many :smart_group_properties, through: :property_operators  
end

例は次のとおりです。

スマートグループ:すべて30-何か。ルール1:年齢が29歳以上の人。ルール2:年齢が40歳未満の人。

プロパティは「年齢」です。「age」プロパティには、より小さい、より大きい、正確な3つの選択可能な演算子があります。ルール1の「値」は29で、ルール2の「値」は31です。

Railscastエピソード#196「ネストされたモデルフォーム(改訂)」のフォームに複数のルールを追加するために、ライアンベイトの手法を使用しています。

#smart_groups/_form.html.erb
<%= simple_form_for(@smart_group) do |f| %>
  <%= f.error_notification %>

 <%= f.input :name %>
 <%= f.input :definition %>

 <%= f.simple_fields_for :rules do |rule_form| %>
  <%= render 'rule_fields', f: rule_form %>
 <% end %>

 <%= link_to_add_fields "Add Rule", f, :rules %>
    <%= f.button :submit %>
<% end %>

#smart_groups/_rule_form.html.erb
 <%= field_set_tag 'Smart Group Rule' do %>
  <%= f.association :smart_group_property, label_method: :prose, input_html: {class: "property_selector"} %>
  <span id="property-fields">

  </span>
  <%= f.hidden_field :_destroy %>
  <%= link_to "remove this rule", '#', class: "remove_fields" %>
 <% end %>

<script type="text/javascript" charset="utf-8">
 $(".property_selector").observe_field(1, function( ) {
  var data = {'property_id' : $(this).val()};
  var url = '/smart_groups/property_selected';
  $.get(url, data, function(html) {
   $("#property_operator").html(html);
  });
 });
</script>
#this is inline because I can't figure out how to do it unobtrusively.

Railscastのヘルパーメソッド。

# ApplicationHelper
  def link_to_add_fields(name, f, association)
      new_object = f.object.send(association).klass.new
      id = new_object.object_id
      fields = f.fields_for(association, new_object, child_index: id) do |builder|
        render(association.to_s.singularize + "_fields", f: builder)
      end
      link_to(name, '#', class: "add_fields", data: {id: id, fields: fields.gsub("\n", "")})
  end

# js.coffee
  $('form').on 'click', '.add_fields', (event) ->
    time = new Date().getTime()
    regexp = new RegExp($(this).data('id'), 'g')
    $(this).before($(this).data('fields').replace(regexp, time))
    event.preventDefault()

このヘルパーは、このコーヒースクリプトとともに、複数のスマートグループルールフォームをページに正常に追加します。

ここで問題があります。ルールフォームでプロパティ値が選択されている場合、フォームの残りの部分は、選択されたプロパティの演算子で更新する必要があります。プロパティセレクターを監視するために、jQuery.observe_fieldプラグインを使用する上記のインラインjsを使用しています。コントローラアクションが呼び出され、選択したプロパティのIDがproperty_idとしてコントローラに送信されます。

class SmartGroupsController < ApplicationController
  def property_selected
    @property = SmartGroupProperty.find(params[:property_id])
    @partial_name = @property.short + "_fields"
  end
end

これにより、変数@partial_nameを設定できます。

次に、選択したプロパティの演算子の部分でビューが更新されます(または「更新する必要があります」)。

#property_selected.js.erb
$("#property-fields").html("<%= j render partial: @partial_name, locals: {f: f} %>");

…しかし、フォームビルダーオブジェクトをフォームに送信する方法がわかりません…または、Rails4を使用してこの方法でアプローチできるかどうかもわかりません。

このエラーが発生します:

ActionView::Template::Error (undefined local variable or method `f' for #< <Class:0x007f9884088120>:0x007f98824c9e98>):
    1: $("#property-fields").html("<%= j render partial: @partial_name, locals: {f: f} %>");
  app/views/smart_groups/property_selected.js.erb:1:in                                _app_views_smart_groups_property_selected_js_erb__2922231718460238483_70146499765020'

フォームのビルダーオブジェクトを_rule_formから、property_selectedアクションを介して、フォームの更新された部分に渡すにはどうすればよいですか?これにアプローチするためのより良い方法はありますか?

入力/指示をありがとう。

4

2 に答える 2

0

gem を生成する動的フォームを使用することをお勧めします。これらの gem には、フォーム DOM 変更のイベント オブザーバーへの js があります。

あなたはこの宝石を見ているかもしれません。 https://github.com/nathanvda/cocoon

于 2014-11-04T18:45:37.910 に答える
0

このパーシャルでフォームビルダー変数を渡すことはできないと思います...しかし、それは本当に必要ありません。fields_forwhich を使用するだけで、個別のパラメーターが作成され、コントローラーで設定されたこのパラメーターで作業できる場合に適しています。

<%=fields_for 'properties' do |extra_fields| %>
  <% ... %>
<% end %>

フォームを送信したときに渡されたパラメーターの種類を development.log で確認してください...

于 2013-07-19T22:21:43.893 に答える