ruby on rails f.select opcje z niestandardowymi atrybutami


115

Mam formularz wyboru oświadczenia, taki jak ten:

= 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ć niestandardowy atrybut HTML do moich opcji, na przykład:

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

2
Railsy nie zapewniają takiej funkcjonalności, będziesz musiał stworzyć pomocnika do stworzenia tego znacznika. Pamiętaj też, że podany przykład nie jest poprawnym kodem HTML.
— Augusto

Wiem, mój przykład nie jest poprawnym html ... Chyba muszę zmienić sposób, aby uzyskać wyniki, które chcę, dzięki!
— el_quick,

Odpowiedzi:


356

Railsy MOGĄ dodawać niestandardowe atrybuty do wybierania opcji, używając istniejącego helpera options_for_select. Prawie udało Ci się to znaleźć w kodzie pytania. Korzystanie z 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 wstępnej selekcji:

<%= 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 zgrupowanych opcji, możesz użyć pomocnika grouped_options_for_select, w ten sposób (jeśli @continents jest tablicą obiektów kontynentów, z których każdy ma metodę krajów):

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

Podziękowania należy się paul @ pogodan, który opublikował informację o znalezieniu tego nie w dokumentach, ale czytając źródło rails. https://web.archive.org/web/20130128223827/http://www.pogodan.com/blog/2011/02/24/custom-html-attributes-in-options-for-select


6

Możesz 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} ] }

Prawidłowo, ale już wspomniano w odpowiedzi Anatortoise House.
— Kelvin

Zaakceptowana odpowiedź nie ilustruje niestandardowych atrybutów używających ruby. Ten robi, więc czuję, że jest lepszy, ponieważ jest to pierwsza odpowiedź, która pokazuje, jak to zrobić za pomocą ruby.
— Nikhil Gupte

5

Nie jest to możliwe bezpośrednio w Railsach i będziesz musiał stworzyć własnego pomocnika do tworzenia niestandardowych atrybutów. To powiedziawszy, prawdopodobnie istnieją dwa różne sposoby osiągnięcia tego, co chcesz:

(1) Używanie niestandardowej nazwy atrybutu w HTML5. W HTML5 możesz mieć niestandardowe nazwy atrybutów , ale muszą one być poprzedzone znakiem „data-”. Te atrybuty niestandardowe nie zostaną przesłane wraz z formularzem, ale można ich użyć do uzyskania dostępu do elementów w JavaScript. Jeśli chcesz to osiągnąć, polecam stworzenie pomocnika, który generuje takie opcje:

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

(2) Używanie wartości z niestandardowym podziałem do przesyłania dodatkowych danych. Jeśli faktycznie chcesz przesłać kod waluty, polecam utworzenie pola wyboru w następujący sposób:

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

Powinno to wygenerować kod HTML, który wygląda następująco:

<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(':')

3
Świetna odpowiedź. Zdecydowałem się na podejście numer 1 i napisałem na blogu, jak zrobiłem pomocnika na wypadek, gdyby pomogło to komukolwiek innemu. redguava.com.au/2011/03/…
— Joel Friedlaender

Zgadzam się z innymi komentatorami - zobacz odpowiedź Anatortoise'a poniżej!
— Jacob,

23
>>>>>>>>>>>>> ZŁA ODPOWIEDŹ ... KEEP SCROLLING <<<<<<<<<<<<<
— stevenspiel

1
Jest to bezpośrednio możliwe w Railsach. Zobacz: stackoverflow.com/a/9076805/380607
— Magne

Pan, usuń tę mylącą odpowiedź.
— vemv

4

Funkcja mieszania dodatkowych atrybutów jest obsługiwana tylko w Railsach 3.

Jeśli korzystasz z Rails 2.x i chcesz przesłonićoptions_for_select

Po prostu skopiowałem kod Rails 3. Musisz zastąpić 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ę niechlujne, ale to opcja. Umieszczam ten kod w module pomocniczym o nazwie, RailsOverridesktóry następnie dołączam do ApplicationHelper. Jeśli wolisz, możesz także zrobić wtyczkę / klejnot.

Jedna trudność polega na tym, że aby skorzystać z tych metod, należy zawsze wywoływać options_for_selectbezpośrednio. Skróty takie jak

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

przyniesie stare rezultaty. Zamiast tego powinno być:

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

Ponownie nie jest to świetne rozwiązanie, ale warto sięgnąć do zawsze tak użytecznego atrybutu danych.


Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.