web-dev-qa-db-fra.com

ruby sur Rails f.selecter des options avec des attributs personnalisés

J'ai une déclaration de sélection de formulaire, comme ceci:

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

Quels sont les résultats dans ce code:

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

Mais je veux ajouter un attribut HTML personnalisé à mes options, comme ceci:

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

Rails PEUT ajouter des attributs personnalisés pour sélectionner des options, en utilisant l’assistant existant options_for_select. Vous avez presque tout compris dans le code de votre question. Utilisation des attributs de données html5:

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

Ajouter une sélection initiale:

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

Si vous avez besoin d'options groupées, vous pouvez utiliser l'assistant grouped_options_for_select, comme ceci (si @continents est un tableau d'objets continent, chacun ayant une méthode 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) %>

Le mérite devrait aller à paul @ pogodan qui a posté sur le fait de ne pas le trouver dans la documentation, mais en lisant le Rails source. https://web.archive.org/web/20130128223827) /http://www.pogodan.com/blog/2011/02/24/custom-html-attributes-in-options-for-select

349
Anatortoise House

Vous pouvez le faire comme suit:

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

Ce n'est pas possible directement avec Rails et vous devrez créer votre propre assistant pour créer les attributs personnalisés. Cela dit, il y a probablement deux façons d'accomplir ce que vous voulez:

(1) Utilisation d'un nom d'attribut personnalisé en HTML5. En HTML5, vous êtes autorisé à avoir noms d'attribut personnalisé , mais ils ont être préparé avec 'data-'. Ces attributs personnalisés ne seront pas soumis avec votre formulaire, mais ils peuvent être utilisés pour accéder à vos éléments en Javascript. Si vous voulez accomplir cela, je vous conseillerais de créer un assistant générant des options telles que:

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

(2) Utilisation de valeurs avec fractionnement personnalisé pour soumettre des données supplémentaires. Si vous souhaitez réellement soumettre le code de devise, je vous recommande de créer votre zone de sélection, comme cette:

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

Cela devrait générer du HTML qui ressemble à ceci:

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

Que vous pouvez ensuite analyser dans votre contrôleur:

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

Le hachage des attributs supplémentaires n’est pris en charge que dans Rails 3.

Si vous êtes sur Rails 2.x et que vous souhaitez remplacer options_for_select

En gros, je viens de copier le code Rails 3. Vous devez remplacer ces 3 méthodes:

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

Un peu désordonné mais c'est une option. Je place ce code dans un module d'aide appelé RailsOverrides que j'inclus ensuite dans ApplicationHelper. Vous pouvez également faire un plugin/gem si vous préférez.

Un des pièges est que pour tirer parti de ces méthodes, vous devez toujours invoquer options_for_select directement. Raccourcis comme

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

donnera les anciens résultats. Au lieu de cela, il devrait être:

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

Encore une fois, ce n’est pas une bonne solution, mais il vaut peut-être la peine d’obtenir l’attribut data toujours aussi utile.

4
mastaBlasta

J'ai rencontré ce problème aussi et créé le "Enhanced_select" Ruby Gem pour résoudre ce problème. Vous pouvez le trouver ici:

https://github.com/bkuhlmann/enhanced_select

0
Brooke Kuhlmann