рубін на рейках. Виберіть параметри зі спеціальними атрибутами


115

У мене є форму вибору форми, наприклад:

= 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

Рейки МОЖУТЬ додати спеціальні атрибути для вибору параметрів, використовуючи наявний помічник 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) %>

Кредит повинен перейти до 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} ] }

Правильна, але вже згадувана у відповіді Анатортоаз Хаус.
Келвін

Прийнята відповідь не ілюструє власні атрибути, що використовують рубін. Це означає, що я вважаю, що це краще, оскільки це перша відповідь, яка показує, як це зробити через рубін.
Нікхіл Гупте

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/…
Джоел Фрідлендер

Погодьтеся з іншими коментаторами - див. Відповідь Anatortoise нижче!
Яків

23
>>>>>>>>>>>>> НЕОБХІДНО ВІДПОВІДАЙТЕ… ПОВЕРНУТИСЯ
СКЛОЛІНГ

1
Це прямо можливо в Rails. Дивіться: stackoverflow.com/a/9076805/380607
Магне

Пан, видаліть цю оманливу відповідь.
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. Ви також можете зробити плагін / дорогоцінний камінь, якщо хочете.

Одним з причин є те, що для того, щоб скористатися цими методами, потрібно завжди звертатися 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"} ] }))

Знову не чудове рішення, але, можливо, варто того, щоб дійти до настільки корисного атрибута даних.


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.