ruby on rails f. pilih opsi dengan atribut khusus

115

Saya memiliki pernyataan pemilihan formulir, seperti ini:

= f.select :country_id, @countries.map{ |c| [c.name, c.id] }

Yang menghasilkan kode ini:

...
<option value="1">Andorra</option>
<option value="2">Argentina</option>
...

Tetapi saya ingin menambahkan atribut HTML khusus ke opsi saya, seperti ini:

...
<option value="1" currency_code="XXX">Andorra</option>
<option value="2" currency_code="YYY">Argentina</option>
...
el_quick
sumber
2
Rails tidak menyediakan fungsionalitas itu, Anda harus membuat helper untuk membuat markup itu. Selain itu, harap diingat bahwa contoh yang Anda sebutkan bukan HTML yang valid.
Augusto
Saya tahu, contoh saya html tidak valid ... Saya kira saya harus mengubah cara saya untuk mendapatkan hasil yang saya inginkan, thk!
el_quick

Jawaban:

356

Rails DAPAT menambahkan atribut khusus untuk memilih opsi, menggunakan pembantu options_for_select yang ada. Anda hampir memasukkannya ke dalam kode pertanyaan Anda. Menggunakan atribut data html5:

<%= f.select :country_id, options_for_select(
    @countries.map{ |c| [c.name, c.id, {'data-currency_code'=>c.currency_code}] }) %>

Menambahkan seleksi awal:

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

Jika Anda memerlukan opsi yang dikelompokkan, Anda dapat menggunakan helper grouped_options_for_select, seperti ini (jika @continents adalah larik objek benua, masing-masing memiliki metode negara):

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

Kredit harus diberikan kepada paul @ pogodan yang memposting tentang menemukan ini bukan di dokumen, tetapi dengan membaca sumber rel. https://web.archive.org/web/20130128223827/http://www.pogodan.com/blog/2011/02/24/custom-html-attributes-in-options-for-select

Anatortoise House
sumber
6

Anda bisa melakukan ini sebagai berikut:

= f.select :country_id, @countries.map{ |c| [c.name, c.id, { 'data-currency-code' => c.currency_code} ] }
Nikhil Gupte
sumber
Benar, tetapi sudah disebutkan dalam jawaban Anatortoise House.
Kelvin
Jawaban yang diterima tidak menggambarkan atribut khusus yang menggunakan ruby. Yang ini melakukannya, saya merasa lebih baik karena ini adalah jawaban pertama yang menunjukkan bagaimana melakukannya melalui ruby.
Nikhil Gupte
5

Ini tidak dapat dilakukan secara langsung dengan Rails, dan Anda harus membuat helper Anda sendiri untuk membuat atribut khusus. Meskipun demikian, mungkin ada dua cara berbeda untuk mencapai apa yang Anda inginkan:

(1) Menggunakan nama atribut khusus di HTML5. Di HTML5 Anda diizinkan untuk memiliki nama atribut khusus , tetapi harus didahului dengan 'data-'. Atribut khusus ini tidak akan dikirimkan bersama formulir Anda, tetapi dapat digunakan untuk mengakses elemen Anda dalam Javascript. Jika Anda ingin melakukannya, saya akan merekomendasikan membuat helper yang menghasilkan opsi seperti ini:

<option value="1" data-currecy-code="XXX">Andorra</option>

(2) Menggunakan nilai dengan pemisahan khusus untuk mengirimkan data tambahan. Jika Anda benar-benar ingin mengirimkan kode mata uang, saya akan merekomendasikan membuat kotak pilih Anda seperti ini:

= f.select :country_id, @countries.map{ |c| [c.name, "#{c.id}:#{c.currency_code}"] }

Ini harus menghasilkan HTML yang terlihat seperti ini:

<option value="1:XXX">Andorra</option>
<option value="2:YYY">Argentina</option>

Yang kemudian dapat Anda parse di pengontrol Anda:

@id, @currency_code = params[:country_id].split(':')
Pan Thomakos
sumber
3
Jawaban yang bagus. Saya telah memilih pendekatan nomor 1 dan menulis blog bagaimana saya membuat helper seandainya itu membantu orang lain. redguava.com.au/2011/03/…
Joel Friedlaender
Setuju dengan pemberi komentar lain - lihat jawaban Anatortoise, di bawah!
Jacob
23
>>>>>>>>>>>>> JAWABAN YANG SALAH ... TERUS MENGGOLONG <<<<<<<<<<<<
stevenspiel
1
Ini secara langsung dimungkinkan di Rails. Lihat: stackoverflow.com/a/9076805/380607
Magne
Pan, tolong hapus jawaban yang menyesatkan ini.
vemv
4

Hash atribut tambahan hanya didukung di Rails 3.

Jika Anda menggunakan Rails 2.x , dan ingin menggantioptions_for_select

Saya pada dasarnya hanya menyalin kode Rails 3. Anda perlu mengganti 3 metode ini:

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

Agak berantakan tapi itu pilihan. Saya menempatkan kode ini dalam modul pembantu yang disebut RailsOverridesyang kemudian saya sertakan ApplicationHelper. Anda juga dapat melakukan plugin / gem jika mau.

Salah satu alasannya adalah untuk memanfaatkan metode ini, Anda harus selalu memanggil options_for_selectsecara langsung. Pintasan seperti

select("post", "person_id", Person.all.collect {|p| [ p.name, p.id, {"data-stuff"=>"html5"} ] })

akan menghasilkan hasil yang lama. Sebaliknya itu harus:

select("post", "person_id", options_for_select(Person.all.collect {|p| [ p.name, p.id, {"data-stuff"=>"html5"} ] }))

Sekali lagi bukan solusi yang bagus, tetapi mungkin layak untuk mendapatkan atribut data yang sangat berguna.

mastaBlasta
sumber
0

Saya mengalami masalah ini juga dan membuat Permata Ruby "Enhanced_select" untuk memecahkan masalah ini. Anda dapat menemukannya di sini:

https://github.com/bkuhlmann/enhanced_select

Brooke Kuhlmann
sumber
2
Ini link ke halaman 404 di github.com
cevaris