ทับทิมบนรางฉเลือกตัวเลือกที่มีคุณลักษณะที่กำหนดเอง


116

ฉันมีคำสั่งเลือกแบบฟอร์มดังนี้:

= 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 data-attributes:

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

เครดิตควรไปที่ 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
Kelvin

คำตอบที่ยอมรับไม่ได้แสดงถึงแอตทริบิวต์ที่กำหนดเองโดยใช้ทับทิม อันนี้ทำให้ฉันรู้สึกดีขึ้นเพราะเป็นคำตอบแรกที่แสดงวิธีการทำผ่านทับทิม
Nikhil Gupte

5

ไม่สามารถทำได้โดยตรงกับ Rails และคุณจะต้องสร้างตัวช่วยของคุณเองเพื่อสร้างแอตทริบิวต์ที่กำหนดเอง ที่กล่าวมาอาจมีสองวิธีที่แตกต่างกันในการบรรลุสิ่งที่คุณต้องการ:

(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/…
Joel Friedlaender

เห็นด้วยกับผู้แสดงความคิดเห็นอื่น ๆ - ดูคำตอบของ Anatortoise ด้านล่าง!
Jacob

23
>>>>>>>>>>>>> คำตอบที่ผิด ... ให้เลื่อน <<<<<<<<<<<<
stevenspiel

1
สิ่งนี้เป็นไปได้โดยตรงใน Rails ดู: stackoverflow.com/a/9076805/380607
Magne

แพนโปรดลบคำตอบที่ทำให้เข้าใจผิดนี้
vemv

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นั้น คุณยังสามารถสร้างปลั๊กอิน / อัญมณีได้หากต้องการ

gotcha หนึ่งคือการใช้ประโยชน์จากวิธีการเหล่านี้คุณต้องเรียกใช้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"} ] }))

อีกครั้งไม่ใช่วิธีแก้ปัญหาที่ยอดเยี่ยม แต่อาจคุ้มค่าที่จะได้รับ data-attribute ที่มีประโยชน์


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.