Ruby on rails f.selectオプションとカスタム属性


115

次のようなフォームselectステートメントがあります。

= 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>
...

2
Railsはその機能を提供していません。そのマークアップを作成するにはヘルパーを作成する必要があります。また、あなたが言及した例は有効なHTMLではないことに注意してください。
アウグスト

私の例は有効なhtmlではありません...私が望む結果を得るには方法を変更する必要があると思います、thk!
el_quick

回答:


356

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


6

これは次のように行うことができます。

= f.select :country_id, @countries.map{ |c| [c.name, c.id, { 'data-currency-code' => c.currency_code} ] }

正解ですが、Anatortoise Houseの回答ですでに言及されています。
ケルビン2013年

受け入れられた答えは、ルビを使用したカスタム属性を示していません。これはそれを行うので、ルビを介してそれを行う方法を示す最初の答えであるため、私はそれがより良いと感じています。
Nikhil Gupte 2013年

5

これは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(':')

3
すばらしい答えです。私はアプローチ番号1を選択し、他の人を助ける場合に備えてヘルパーを作成した方法をブログに書いています。redguava.com.au/2011/03/...
ジョエルFriedlaender

他のコメンテーターと同意します-以下のAnatortoiseの回答を参照してください!
Jacob

23
>>>>>>>>>>>>> WRONG ANSWER ... KEEP SCROLLING <<<<<<<<<<<<
stevenspiel 2014年

1
これはRailsで直接可能です。参照:stackoverflow.com/a/9076805/380607
Magne

パン、この誤解を招く答えを削除してください。
vemv 2016年

4

追加の属性ハッシュはRails 3でのみサポートされます。

あなたは、にしている場合のRails 2.xの、および上書きします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。必要に応じて、plugin / gemを実行することもできます。

これらのメソッドを利用するには、常に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"} ] }))

ここでも優れたソリューションではありませんが、これまでになく有用なデータ属性を取得することは価値があるかもしれません。


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.