ruby on rails f. wybierz opcje z własnymi atrybutami

Mam polecenie form select, takie jak:

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

Co daje ten kod:

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

Ale chcę dodać własny atrybut HTML do moich opcji, jak to:

...
<option value="1" currency_code="XXX">Andorra</option>
<option value="2" currency_code="YYY">Argentina</option>
...
Author: Daniel Rikowski, 2011-02-19

5 answers

Rails może dodawać własne atrybuty do wyboru opcji, używając istniejącego helpera options_for_select. Prawie miałeś rację w kodzie w swoim pytaniu. Używanie atrybutów danych html5:

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

Dodanie początkowego wyboru:

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

Jeśli potrzebujesz opcji zgrupowanych, możesz użyć helpera grouped_options_for_select, w ten sposób (jeśli @ continents jest tablicą obiektów kontynentu, z których każdy ma metodę countries):

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

Kredyt powinien iść do Pawła @ pogodan, który napisał o znajdowanie tego nie w dokumentach, ale poprzez odczytanie źródła rails. https://web.archive.org/web/20130128223827/http://www.pogodan.com/blog/2011/02/24/custom-html-attributes-in-options-for-select

 332
Author: Anatortoise House,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-14 20:01:34

Nie jest to możliwe bezpośrednio z Rails i będziesz musiał stworzyć własnego pomocnika, aby utworzyć własne atrybuty. To powiedziawszy, są prawdopodobnie dwa różne sposoby, aby osiągnąć to, co chcesz:

(1) używanie niestandardowej nazwy atrybutu w HTML5. w HTML5 możesz mieć niestandardowe nazwy atrybutów , ale muszą być wstępnie dodane przez ' data -'. Te niestandardowe atrybuty nie zostaną przesłane wraz z formularzem, ale mogą być użyte do uzyskania dostępu do elementów w Javascript. Jeśli chcesz to osiągnąć, polecam stworzenie helpera, który generuje opcje takie jak:

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

(2) używanie wartości z niestandardowym dzieleniem do przesyłania dodatkowych danych. Jeśli chcesz podać kod waluty, polecam utworzenie twojego pola wyboru w następujący sposób:

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

To powinno wygenerować HTML, który wygląda tak:

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

Które możesz następnie przeanalizować w kontrolerze:

@id, @currency_code = params[:country_id].split(':')
 6
Author: Pan Thomakos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-19 20:55:18

Można to zrobić w następujący sposób:

= f.select :country_id, @countries.map{ |c| [c.name, c.id, { 'data-currency-code' => c.currency_code} ] }
 6
Author: Nikhil Gupte,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-28 04:55:44

Dodatkowe atrybuty hash są obsługiwane tylko w Rails 3.

Jeśli jesteś na Rails 2.x , i chcesz nadpisać options_for_select

W zasadzie skopiowałem Kod Rails 3. Musisz nadpisać te 3 metody:

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

Trochę bałagan, ale to jest opcja. Umieszczam ten kod w module pomocniczym o nazwie RailsOverrides, który następnie dołączam do ApplicationHelper. Możesz również zrobić wtyczkę / gem, jeśli wolisz.

Jednym z nich jest to, że aby skorzystać z tych metod trzeba zawsze wywoływać Bezpośrednio. Skróty jak

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

Da stare wyniki. Zamiast tego powinno być:

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

Znowu nie jest to świetne rozwiązanie, ale może warto sięgnąć do tak przydatnych danych-atrybutu.

 4
Author: mastaBlasta,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-19 22:42:54

Napotkałem również ten problem i stworzyłem klejnot Ruby" enhanced_select", aby rozwiązać ten problem. Można go znaleźć tutaj:

Https://github.com/bkuhlmann/enhanced_select

 0
Author: Brooke Kuhlmann,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-04 16:30:29