web-dev-qa-db-fra.com

Enregistrement de l’énumération de sélectionner dans Rails 4.1

J'utilise les enums de Rails 4.1 pour suivre les couleurs du vin.

Wine.rb

class Wine < ActiveRecord::Base
    enum color: [:red, :white, :sparkling]
end

À mon avis, je génère une sélection afin que l'utilisateur puisse sélectionner un vin d'une certaine couleur

f.input :color, :as => :select, :collection => Wine.colors

Cela génère le code HTML suivant:

<select id="wine_color" name="wine[color]">
  <option value=""></option>
  <option value="0">red</option>
  <option value="1">white</option>
  <option value="2">sparkling</option>
</select>

Cependant, lors de la soumission du formulaire, je reçois une erreur d’argument indiquant '1' is not a valid color. Je réalise que c'est parce que color doit être égal à 1 et pas "1".

Existe-t-il un moyen de forcer Rails pour interpréter la couleur comme un entier plutôt que comme une chaîne)?

98
Brian Weinreich

Bon, apparemment, vous ne devriez pas envoyer la valeur entière de l’énum à enregistrer. Vous devriez envoyer la valeur textuelle de l'énum.

J'ai changé l'entrée comme suit:

f.input :color, :as => :select, :collection => Wine.colors.keys.to_a

Qui a généré le code HTML suivant:

<select id="wine_color" name="wine[color]">
  <option value=""></option>
  <option value="red">red</option>
  <option value="white">white</option>
  <option value="sparkling">sparkling</option>
</select>

Les valeurs sont passées de "0" à "rouge" et maintenant tout est prêt.


Si vous utilisez un ol classique Rails text_field, c'est:

f.select :color, Wine.colors.keys.to_a


Si vous voulez avoir des attributs propres lisibles par l'homme, vous pouvez aussi faire:

f.select :color, Wine.colors.keys.map { |w| [w.humanize, w] }

194
Brian Weinreich

Pas besoin de convertir le hash enum en tableau avec to_a. Cela suffit:

f.select :color, Wine.colors.map { |key, value| [key.humanize, key] }
30
Fellow Stranger

La solution acceptée ne fonctionnait pas pour moi pour le lisible par l'homme, mais j'ai pu le faire fonctionner comme ceci:

<%= f.select(:color, Wine.colors.keys.map {|key| [key.humanize, key]}) %>

C'était le plus propre, mais j'avais vraiment besoin d'humaniser mes clés:

<%= f.select(:color, Wine.colors.keys) %>
9
Tom Rossi

Je viens de mettre sur pied un EnumHelper que je pensais partager pour aider les personnes qui ont besoin de plus d’étiquettes et d’environnements enum personnalisés pour votre sélection d’enum.

module EnumHelper

  def options_for_enum(object, enum)
    options = enums_to_translated_options_array(object.class.name, enum.to_s)
    options_for_select(options, object.send(enum))
  end

  def enums_to_translated_options_array(klass, enum)
    klass.classify.safe_constantize.send(enum.pluralize).map {
        |key, value| [I18n.t("activerecord.enums.#{klass.underscore}.#{enum}.#{key}"), key]
    }
  end

end

Dans votre région:

 en:
   activerecord:
     enums:
      wine:
        color:
          red:   "Red Wine"
          white:  "White Wine"

Dans vos vues:

 <%= f.select(:color, options_for_enum(@wine, :color)) %>
8
Andrew Cetinic

Si vous utilisez enum dans Rails 4, appelez simplement Model.enums:

f.select :color, Wine.colors.keys

Pour créer du HTML:

<select name="f[color]" id="f_color">
    <option value="red">red</option>
    <option value="white">white</option>
    <option value="sparkling"> sparkling </option>
</select>

Ou ajouter une méthode dans le contrôleur:

def update_or_create
    change_enum_to_i
    ....
end

def change_enum_to_i
    params[:f]["color"] = params[:f]["color"].to_i
end
6
ogelacinyc

Voici ce qui a fonctionné pour moi, Rails 4+:

class Contract < ApplicationRecord

enum status: { active:  "active", 
               ended: "active", 
               on_hold: "on_hold", 
               terminated:  "terminated", 
               under_review:  "under_review" , 
               unknown: "unknown" 
              }


end

dans my _form.html.erb , J'ai ceci:

  <div class="field">
    <%= form.select :status, Contract.statuses.keys, {}%>
  </div>

test depuis la console après avoir ajouté un enregistrement:

2.3.0 :001 > Contract.last.status
  Contract Load (0.2ms)  SELECT  "contracts".* FROM "contracts" ORDER BY "contracts"."id" DESC LIMIT ?  [["LIMIT", 1]]
 => "active"
3
zee

Si vous devez gérer l'i18n en fonction des clés d'enum, vous pouvez utiliser:

<%= f.select :color, Wine.colors.keys.map {|key| [t("wine.#{key}"), key]} %>

et dans les traductions, vous pouvez définir les couleurs:

wine:
 red: Red
 white: White
2
Paulo Fidalgo

Voici ma solution (mes rôles sont soulignés comme "sales_rep"), et pour une raison quelconque, voici comment je devais obtenir une option vide pour travailler (avec simpleform?):

Dans ApplicationHelper:

def enum_collection_for_select(attribute, include_blank = true)
  x = attribute.map { |r| [r[0].titleize, r[0]] }
  x.insert(0,['', '']) if include_blank == true
  x
end

Puis sous ma forme:

<%= f.input :role, collection: enum_collection_for_select(User.roles), selected: @user.role %>
1
Greg Blass