次のようなフォーム選択ステートメントがあります。
= f.select :country_id, @countries.map{ |c| [c.name, c.id] }
このコードの結果:
...
<option value="1">Andorra</option>
<option value="2">Argentina</option>
...
しかし、次のように、オプションにカスタムHTML属性を追加したいと思います。
...
<option value="1" currency_code="XXX">Andorra</option>
<option value="2" currency_code="YYY">Argentina</option>
...
Railsは、既存のoptions_for_selectヘルパーを使用して、選択オプションにカスタム属性を追加できます。あなたはあなたの質問のコードでほとんどそれを正しく持っていました。 html5データ属性の使用:
<%= f.select :country_id, options_for_select(
@countries.map{ |c| [c.name, c.id, {'data-currency_code'=>c.currency_code}] }) %>
初期選択の追加:
<%= f.select :country_id, options_for_select(
@countries.map{ |c| [c.name, c.id, {'data-currency_code'=>c.currency_code}] },
selected_key = f.object.country_id) %>
グループ化されたオプションが必要な場合は、grouped_options_for_selectヘルパーを次のように使用できます(@continentsが大陸オブジェクトの配列で、それぞれに国メソッドがある場合):
<%= f.select :country_id, grouped_options_for_select(
@continents.map{ |group| [group.name, group.countries.
map{ |c| [c.name, c.id, {'data-currency_code'=>c.currency_code}] } ] },
selected_key = f.object.country_id) %>
クレジットは、ドキュメントではなくRailsのソースを読んで、これを見つけることについて投稿したpaul @ pogodanに送ってください。 https://web.archive.org/web/20130128223827/http://www.pogodan.com/blog/2011/02/24/custom-html-attributes-in-options-for-select
これは次のように実行できます。
= f.select :country_id, @countries.map{ |c| [c.name, c.id, { 'data-currency-code' => c.currency_code} ] }
これはRailsで直接行うことはできません。独自のヘルパーを作成して、カスタム属性を作成する必要があります。とは言っても、おそらくあなたが望むことを達成するための2つの異なる方法があります。
(1)HTML5でカスタム属性名を使用します。HTML5では、 カスタム属性名 を使用できますが、 「data-」が先頭に追加されます。これらのカスタム属性はフォームとともに送信されませんが、Javascriptの要素にアクセスするために使用できます。これを達成したい場合は、次のようなオプションを生成するヘルパーを作成することをお勧めします。
<option value="1" data-currecy-code="XXX">Andorra</option>
(2)カスタム分割で値を使用して追加データを送信します。実際に通貨コードを送信する場合は、次のような選択ボックスを作成することをお勧めしますこの:
= f.select :country_id, @countries.map{ |c| [c.name, "#{c.id}:#{c.currency_code}"] }
これにより、次のようなHTMLが生成されます。
<option value="1:XXX">Andorra</option>
<option value="2:YYY">Argentina</option>
これをコントローラーで解析できます:
@id, @currency_code = params[:country_id].split(':')
追加の属性ハッシュは、Rails 3でのみサポートされます。
options_for_select
をオーバーライドする場合基本的に、Rails 3コードをコピーしました。次の3つのメソッドをオーバーライドする必要があります。
def options_for_select(container, selected = nil)
return container if String === container
container = container.to_a if Hash === container
selected, disabled = extract_selected_and_disabled(selected)
options_for_select = container.inject([]) do |options, element|
html_attributes = option_html_attributes(element)
text, value = option_text_and_value(element)
selected_attribute = ' selected="selected"' if option_value_selected?(value, selected)
disabled_attribute = ' disabled="disabled"' if disabled && option_value_selected?(value, disabled)
options << %(<option value="#{html_escape(value.to_s)}"#{selected_attribute}#{disabled_attribute}#{html_attributes}>#{html_escape(text.to_s)}</option>)
end
options_for_select.join("\n").html_safe
end
def option_text_and_value(option)
# Options are [text, value] pairs or strings used for both.
case
when Array === option
option = option.reject { |e| Hash === e }
[option.first, option.last]
when !option.is_a?(String) && option.respond_to?(:first) && option.respond_to?(:last)
[option.first, option.last]
else
[option, option]
end
end
def option_html_attributes(element)
return "" unless Array === element
html_attributes = []
element.select { |e| Hash === e }.reduce({}, :merge).each do |k, v|
html_attributes << " #{k}=\"#{ERB::Util.html_escape(v.to_s)}\""
end
html_attributes.join
end
ちょっと面倒ですが、それはオプションです。このコードをRailsOverrides
というヘルパーモジュールに配置し、ApplicationHelper
に含めます。必要に応じて、プラグイン/宝石を行うこともできます。
1つの落とし穴は、これらのメソッドを利用するには、常にoptions_for_select
を直接呼び出す必要があることです。のようなショートカット
select("post", "person_id", Person.all.collect {|p| [ p.name, p.id, {"data-stuff"=>"html5"} ] })
古い結果が得られます。代わりに:
select("post", "person_id", options_for_select(Person.all.collect {|p| [ p.name, p.id, {"data-stuff"=>"html5"} ] }))
再び素晴らしい解決策ではありませんが、これまでにない便利なデータ属性を取得する価値があります。
私もこの問題に遭遇し、この問題を解決するために「enhanced_select」Ruby Gemを作成しました。ここで見つけることができます: