ruby trên đường ray f.select tùy chọn với các thuộc tính tùy chỉnh


115

Tôi có một tuyên bố chọn biểu mẫu, như thế này:

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

Kết quả nào trong mã này:

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

Nhưng tôi muốn thêm một thuộc tính HTML tùy chỉnh vào các tùy chọn của mình, như thế này:

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

2
Rails không cung cấp chức năng đó, bạn sẽ phải tạo một người trợ giúp để tạo đánh dấu đó. Ngoài ra, hãy nhớ rằng ví dụ bạn đề cập không phải là HTML hợp lệ.
Augusto

Tôi biết, ví dụ của tôi không hợp lệ html ... Tôi đoán tôi phải thay đổi cách của mình để có được kết quả mà tôi muốn, thk!
el_quick

Câu trả lời:


356

Rails CÓ THỂ thêm các thuộc tính tùy chỉnh để chọn tùy chọn, sử dụng trình trợ giúp tùy chọn_for_select hiện có. Bạn gần như đã có nó ngay trong mã trong câu hỏi của bạn. Sử dụng các thuộc tính dữ liệu html5:

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

Thêm lựa chọn ban đầu:

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

Nếu bạn cần các tùy chọn được nhóm, bạn có thể sử dụng trình trợ giúp grouped_options_for_select, như thế này (nếu @continents là một mảng các đối tượng lục địa, mỗi đối tượng có một phương thức country):

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

Tín dụng nên đến paul @ pogodan, người đã đăng về việc tìm thấy điều này không phải trong các tài liệu, mà bằng cách đọc nguồn đường ray. https://web.archive.org/web/20130128223827/http://www.pogodan.com/blog/2011/02/24/custom-html-attribut-in-options-for-select


6

Bạn có thể làm điều này như sau:

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

Đúng, nhưng đã được đề cập trong câu trả lời của Anatortoir House.
Kelvin

Câu trả lời được chấp nhận không minh họa các thuộc tính tùy chỉnh bằng ruby. Câu hỏi này vì thế tôi cảm thấy tốt hơn vì đây là câu trả lời đầu tiên chỉ ra cách thực hiện thông qua ruby.
Nikhil Gupte

5

Điều này không thể thực hiện trực tiếp với Rails và bạn sẽ phải tạo người trợ giúp của riêng mình để tạo các thuộc tính tùy chỉnh. Điều đó nói rằng, có lẽ có hai cách khác nhau để thực hiện những gì bạn muốn:

(1) Sử dụng tên thuộc tính tùy chỉnh trong HTML5. Trong HTML5, bạn được phép có tên thuộc tính tùy chỉnh , nhưng chúng phải được đặt trước với 'data-'. Các thuộc tính tùy chỉnh này sẽ không được gửi cùng với biểu mẫu của bạn, nhưng chúng có thể được sử dụng để truy cập các phần tử của bạn trong Javascript. Nếu bạn muốn thực hiện điều này, tôi khuyên bạn nên tạo một trình trợ giúp tạo các tùy chọn như thế này:

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

(2) Sử dụng các giá trị với phân tách tùy chỉnh để gửi dữ liệu bổ sung. Nếu bạn thực sự muốn gửi mã tiền tệ, tôi khuyên bạn nên tạo hộp chọn của bạn như thế này:

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

Điều này sẽ tạo ra HTML trông như thế này:

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

Mà bạn có thể phân tích cú pháp trong bộ điều khiển của bạn:

@id, @currency_code = params[:country_id].split(':')

3
Câu trả lời chính xác. Tôi đã chọn cách tiếp cận số 1 và viết blog về cách tôi tạo ra người trợ giúp trong trường hợp nó giúp được ai khác. redguava.com.au/2011/03/ từ
Joel Friedlaender

Đồng ý với những người bình luận khác - xem câu trả lời của Anatortoir, bên dưới!
Jacob

23
>>>>>>>>>>>>> WRONG ĐÁP ... Tiếp tục cuộn <<<<<<<<<<<<
stevenspiel

1
Điều này có thể trực tiếp trong Rails. Xem: stackoverflow.com/a/9076805/380607
Magne

Pan, xin vui lòng xóa câu trả lời sai lệch này.
vemv

4

Hàm băm thuộc tính bổ sung chỉ được hỗ trợ trong Rails 3.

Nếu bạn đang sử dụng Rails 2.x và muốn ghi đèoptions_for_select

Tôi về cơ bản chỉ cần sao chép mã Rails 3. Bạn cần ghi đè 3 phương thức sau:

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

Kinda lộn xộn nhưng đó là một lựa chọn. Tôi đặt mã này trong một mô-đun trợ giúp được gọi là RailsOverridessau đó tôi đưa vào ApplicationHelper. Bạn cũng có thể làm một plugin / đá quý nếu bạn thích.

Một điều đáng chú ý là để tận dụng các phương thức này, bạn phải luôn gọi options_for_selecttrực tiếp. Các phím tắt như

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

sẽ mang lại kết quả cũ. Thay vào đó nên là:

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

Một lần nữa không phải là một giải pháp tuyệt vời, nhưng nó có thể đáng để đi đến thuộc tính dữ liệu hữu ích như vậy.


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.