Ruby on Rails f. Wählen Sie Optionen mit benutzerdefinierten Attributen

115

Ich habe eine Formularauswahlanweisung wie folgt:

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

Was zu diesem Code führt:

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

Ich möchte meinen Optionen jedoch ein benutzerdefiniertes HTML-Attribut hinzufügen:

...
<option value="1" currency_code="XXX">Andorra</option>
<option value="2" currency_code="YYY">Argentina</option>
...
el_quick
quelle
2
Rails bietet diese Funktionalität nicht. Sie müssen einen Helfer erstellen, um dieses Markup zu erstellen. Beachten Sie auch, dass das von Ihnen erwähnte Beispiel kein gültiges HTML ist.
Augusto
Ich weiß, mein Beispiel ist kein gültiges HTML ... Ich denke, ich muss meinen Weg ändern, um die gewünschten Ergebnisse zu erzielen, danke!
el_quick

Antworten:

356

Schienen KÖNNEN benutzerdefinierte Attribute hinzufügen, um Optionen auszuwählen, indem der vorhandene Hilfsprogramm options_for_select verwendet wird. Sie hatten es fast richtig im Code in Ihrer Frage. Verwenden von HTML5-Datenattributen:

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

Hinzufügen einer ersten Auswahl:

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

Wenn Sie gruppierte Optionen benötigen, können Sie den Helfer grouped_options_for_select wie folgt verwenden (wenn @continents ein Array von Kontinentobjekten ist, die jeweils eine Ländermethode haben):

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

Der Kredit sollte an paul @ pogodan gehen, der darüber geschrieben hat, dass dies nicht in den Dokumenten, sondern durch Lesen der Rails-Quelle gefunden wurde. https://web.archive.org/web/20130128223827/http://www.pogodan.com/blog/2011/02/24/custom-html-attributes-in-options-for-select

Anatortoise Haus
quelle
6

Sie können dies wie folgt tun:

= f.select :country_id, @countries.map{ |c| [c.name, c.id, { 'data-currency-code' => c.currency_code} ] }
Nikhil Gupte
quelle
Richtig, aber bereits in der Antwort von Anatortoise House erwähnt.
Kelvin
Die akzeptierte Antwort veranschaulicht die benutzerdefinierten Attribute nicht mit Ruby. Ich denke, es ist besser, da es die erste Antwort ist, die zeigt, wie man es über Ruby macht.
Nikhil Gupte
5

Dies ist nicht direkt mit Rails möglich, und Sie müssen Ihren eigenen Helfer erstellen, um die benutzerdefinierten Attribute zu erstellen. Das heißt, es gibt wahrscheinlich zwei verschiedene Möglichkeiten, um das zu erreichen, was Sie wollen:

(1) Verwenden eines benutzerdefinierten Attributnamens in HTML5. In HTML5 dürfen Sie benutzerdefinierte Attributnamen haben , denen jedoch 'data-' vorangestellt werden muss. Diese benutzerdefinierten Attribute werden nicht mit Ihrem Formular gesendet, können jedoch für den Zugriff auf Ihre Elemente in Javascript verwendet werden. Wenn Sie dies erreichen möchten, würde ich empfehlen, einen Helfer zu erstellen, der folgende Optionen generiert:

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

(2) Verwenden von Werten mit benutzerdefinierter Aufteilung, um zusätzliche Daten zu übermitteln. Wenn Sie den Währungscode tatsächlich einreichen möchten, würde ich empfehlen, Ihr Auswahlfeld wie folgt zu erstellen:

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

Dies sollte HTML generieren, das so aussieht:

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

Was Sie dann in Ihrem Controller analysieren können:

@id, @currency_code = params[:country_id].split(':')
Pan Thomakos
quelle
3
Gute Antwort. Ich habe mich für Ansatz Nummer 1 entschieden und gebloggt, wie ich den Helfer gemacht habe, falls er jemand anderem hilft. redguava.com.au/2011/03/…
Joel Friedlaender
Stimmen Sie anderen Kommentatoren zu - siehe Anatortoises Antwort unten!
Jacob
23
>>>>>>>>>>>>> FALSCHE ANTWORT ... SCROLLING BEHALTEN <<<<<<<<<<<<
Stevenspiel
1
Dies ist direkt in Rails möglich. Siehe: stackoverflow.com/a/9076805/380607
Magne
Pan, bitte löschen Sie diese irreführende Antwort.
vemv
4

Der zusätzliche Attribut-Hash wird nur in Rails 3 unterstützt.

Wenn Sie sich auf Rails 2.x befinden und überschreiben möchtenoptions_for_select

Ich habe im Grunde nur den Rails 3-Code kopiert. Sie müssen diese 3 Methoden überschreiben:

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

Ein bisschen chaotisch, aber es ist eine Option. Ich platziere diesen Code in einem Hilfsmodul namens, RailsOverridesdas ich dann einbinde ApplicationHelper. Sie können auch ein Plugin / Gem erstellen, wenn Sie dies bevorzugen.

Um diese Methoden nutzen zu können, müssen Sie immer options_for_selectdirekt aufrufen . Verknüpfungen wie

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

wird die alten Ergebnisse liefern. Stattdessen sollte es sein:

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

Wieder keine großartige Lösung, aber es könnte sich lohnen, zu dem noch so nützlichen Datenattribut zu gelangen.

mastaBlasta
quelle
0

Ich bin auch auf dieses Problem gestoßen und habe den Ruby Gem "Enhanced_select" erstellt, um dieses Problem zu lösen. Sie finden es hier:

https://github.com/bkuhlmann/enhanced_select

Brooke Kuhlmann
quelle
2
Dieser Link führt zu einer 404-Seite auf github.com
cevaris