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)?
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] }
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] }
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) %>
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)) %>
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
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"
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
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 %>