Traitement des exceptions d'enregistrement uniques dans un contrôleur
J'ai un modèle d'Abonnement, qui a un index unique sur les champs [:email, :emplacement]. Cela signifie une adresse e-mail peut s'abonner par emplacement.
Dans mon modèle:
class Subscription < ActiveRecord::Base
validates :email, :presence => true, :uniqueness => true, :email_format => true, :uniqueness => {:scope => :location}
end
Dans ma méthode de création. Je veux gérer l'exception ActiveRecord::RecordNotUnique
différemment qu'une simple erreur. Comment pourrais-je ajouter que, dans ce générique de la méthode de création?
def create
@subscription = Subscription.new(params[:subscription])
respond_to do |format|
if @subscription.save
format.html { redirect_to(root_url, :notice => 'Subscription was successfully created.') }
else
format.html { render :action => 'new' }
end
end
end
source d'informationauteur Dex
Vous devez vous connecter pour publier un commentaire.
Je ne pense pas qu'il y est un moyen d'avoir une exception juste pour un seul type d'échec de la validation. Vous pouvez faire un
save!
qui permettrait de lever des exceptions pour tous les sauver des erreurs (y compris toutes les erreurs de validation) et de les gérer séparément.Ce que vous pouvez faire est de traiter l'exception
ActiveRecord::RecordInvalid
et match le message d'exception avecValidation failed: Email has already been taken
et de gérer séparément. Mais cela signifie également que vous aurez à gérer d'autres trop d'erreurs.Quelque chose comme,
Je ne suis pas sûr si c'est la seule solution à ce bien.
Un couple de choses que je changerais sur la validation:
Faire de la présence, de l'unicité, et le format des validations dans la validation distincte. (Votre unicité de la clé dans les attributs de hachage vous êtes de passage à "valide" est écrasé dans votre validation). Je voudrais le faire paraître plus comme:
validates_uniqueness_of :email, :portée => :emplacement
validates_presence_of :e-mail
validates_format_of :email, :avec => RFC_822 # Nous utilisons de validation mondial regexes
Les Validations niveau de l'Application, l'une des raisons pour lesquelles vous devez les séparer est parce que la présence et le format des validations peut être fait sans toucher à la base de données. L'unicité de validation de toucher la base de données, mais ne les utilise pas l'index unique que vous l'installation. Le niveau d'Application des validations de ne pas interagir avec la base de données internes qu'ils génèrent SQL et sur la base des résultats de la requête de faire une détermination de la validité. Vous pouvez laisser le validates_uniqueness_of mais être prêt pour les conditions de course dans votre application.
Depuis la validation de la demande est de niveau, il va demander à la ligne (quelque chose comme "SELECT * from abonnements OÙ email = 'email_address' LIMIT 1"), si une ligne est renvoyée à la validation échoue. Si une ligne n'est pas retourné alors elle est considérée comme valide.
Cependant, si dans le même temps quelqu'un d'autre signe avec la même adresse e-mail et ils ne retournent pas de ligne avant d'en créer un nouveau, puis la 2e "enregistrer" livraison qui va déclencher l'unicité de la Base de données de l'indice de contrainte sans déclenchement de la validation dans l'application. (Depuis plus probable qu'ils sont en cours d'exécution sur les différents serveurs d'application, ou du moins différente de VM ou de processus).
ActiveRecord::RecordInvalid est soulevée lors de la validation échoue, et non pas lorsque la contrainte unique de l'index sur la base de données est violé. (Il y a plusieurs niveaux d'ActiveRecord Exceptions qui peuvent être déclenchés à différents points de la demande de réponse du cycle de vie)
RecordInvalid est soulevée dès le premier niveau (niveau Application) alors que RecordNotUnique peuvent être soulevées après la présentation est tenté et le serveur de base de données détermine l'opération ne respecte pas l'indice de contrainte. (ActiveRecord::StatementInvalid est le parent de la poste chercher de l'Exception qui seront soulevées dans cette instance, et vous devez le sauver si vous êtes vraiment essayer d'obtenir la base de données de la rétroaction et de la Demande de validation de niveau)
Si vous êtes dans votre contrôleur "rescue_from" (comme indiqué par L'Oms) devrait fonctionner très bien pour récupérer à partir de ces différents types d'erreurs et il semble que l'intention initiale était de les traiter différemment de sorte que vous pouvez le faire avec plusieurs "rescue_from" appels.
Vous souhaitez utiliser
rescue_from
Dans votre contrôleur
Cependant, vous ne voudriez pas à l'annulation de votre enregistrement plutôt que de lancer une exception?
Ajoutant à Chirantans réponse, avec des Rails 5 (ou 3/4, avec cette Backport) vous pouvez également utiliser la nouvelle
errors.details
:Ce qui est très pratique pour différencier les différents
RecordInvalid
types et ne nécessite pas de compter sur les exceptions message d'erreur.Noter qu'il comprend toutes les erreurs signalées par la validation des processus, ce qui rend la manipulation de plusieurs unicité de validation des erreurs beaucoup plus facile.
Par exemple, vous pouvez vérifier si tous de validation-les erreurs d'un modèle d'attribut sont juste unicité-erreurs:
Ce joyau sauve l'échec de contrainte au niveau du modèle et ajoute une erreur de modèle (model.les erreurs) afin qu'il se comporte comme les autres échecs de validation. Profitez-en! https://github.com/reverbdotcom/rescue-unique-constraint