Comment puis-je spécifier et valider une énumération dans rails?
J'ai actuellement un modèle Attend qui aura une colonne d'état, et cette colonne d'état n'aura que quelques valeurs pour cela. STATUS_OPTIONS = {: oui,: non,: peut-être}
1) Je ne suis pas sûr de savoir comment valider cela avant qu'un utilisateur insère une participation? Fondamentalement, une énumération en java mais comment pourrais-je le faire dans rails?
7 réponses
Créez un tableau globalement accessible des options souhaitées, puis validez la valeur de votre colonne status:
class Attend < ActiveRecord::Base
STATUS_OPTIONS = %w(yes no maybe)
validates :status, :inclusion => {:in => STATUS_OPTIONS}
end
Vous pouvez alors accéder aux statuts possibles via Attend::STATUS_OPTIONS
Maintenant que Rails 4.1
inclut des énumérations, vous pouvez faire ce qui suit:
class Attend < ActiveRecord::Base
enum size: [:yes, :no, :maybe]
# also can use the %i() syntax for an array of symbols:
# %i(yes no maybe)
validates :size, inclusion: { in: sizes.keys }
end
Qui vous fournit alors une portée (ie: Attend.yes
, Attend.no
, Attend.maybe
pour chacun une méthode checker pour voir si un certain statut est défini (ie: #yes?
, #no?
, #maybe?
), avec les méthodes de setter d'attribut (ie: #yes!
, #no!
, #maybe!
).
C'est ainsi que j'implémente dans mon projet Rails 4.
class Attend < ActiveRecord::Base
enum size: [:yes, :no, :maybe]
validates :size, inclusion: { in: Attend.sizes.keys }
end
Assister.tailles vous donne la cartographie.
Attend.sizes # {"yes" => 0, "no" => 1, "maybe" => 2}
, Vous pouvez utiliser une colonne de type chaîne pour le statut et puis l':inclusion
option pour validates
pour s'assurer que vous obtenez seulement ce que vous attendez:
class Attend < ActiveRecord::Base
validates :size, :inclusion => { :in => %w{yes no maybe} }
#...
end
Ce que nous avons commencé à faire est de définir nos éléments enum dans un tableau, puis d'utiliser ce tableau pour spécifier l'enum, les validations et utiliser les valeurs dans l'application.
STATUS_OPTIONS = [:yes, :no, :maybe]
enum status_option: STATUS_OPTIONS
validates :status_option, inclusion: { in: STATUS_OPTIONS.map {|t| t.to_s } }
De cette façon, vous pouvez également utiliser STATUS_OPTIONS plus tard, comme pour créer une liste déroulante. Si vous voulez exposer vos valeurs à l'utilisateur, vous pouvez toujours Mapper comme ceci:
STATUS_OPTIONS.map {|s| s.to_s.titleize }
Après quelques recherches, Je ne pouvais pas trouver un one-liner dans le modèle pour l'aider à se produire. À l'heure actuelle, Rails fournit des énumérations, mais pas un moyen complet de valider des valeurs non valides.
J'ai donc opté pour une solution composite: ajouter une validation dans le contrôleur, avant de définir le strong_params
, puis en vérifiant par rapport au modèle.
Donc, dans le modèle, je vais créer un attribut et une validation personnalisée:
assister à.rb
enum :status => { your set of values }
attr_accessor :invalid_status
validate :valid_status
#...
private
def valid_status
if self.invalid_status == true
errors.add(:status, "is not valid")
end
end
Aussi, je vais faire un chèque contre les paramètres d'entrée non valide et envoyer le résultat (si nécessaire) au modèle, donc une erreur sera ajoutée à l'objet, le rendant ainsi invalide
attends_controller.rb
private
def attend_params
#modify strong_params to include the additional check
if params[:attend][:status].in?(Attend.statuses.keys << nil) # to also allow nil input
# Leave this as it was before the check
params.require(:attend).permit(....)
else
params[:attend][:invalid_status] = true
# remove the 'status' attribute to avoid the exception and
# inject the attribute to the params to force invalid instance
params.require(:attend).permit(...., :invalid_status)
end
end