動作中のアプリを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アクションを介して、フォームの更新された部分に渡すにはどうすればよいですか?これにアプローチするためのより良い方法はありますか?
入力/指示をありがとう。