11
votes

Comment puis-je faire rubis sur les rails à des erreurs d'enregistrement en double duplicate de MySQL

J'ai un index unique sur plusieurs champs de ma base de données. Donc, si vous essayez d'appeler économiser sur un enregistrement en double, il augmente Activerecord :: relevéinvalid et affiche l'erreur MySQL. Existe-t-il un moyen de gérer cela dans les rails, soit en créant la contrainte unique, sinon avoir un message d'erreur pertinent lorsque cela se produit?

Heres la trace: P>

ActiveRecord::StatementInvalid: Mysql::Error: Duplicate entry '2010-12-09-2-0-1-1' for key 2: INSERT INTO `entries` (`rejected_at`, `created_at`, `comments`, `overtime`, `submitted_at`, `updated_at`, `time`, `approved`, `day`, `user_id`, `approved_at`, `job_id`, `submitted`, `rejected`) VALUES(NULL, '2010-12-09 21:50:46', NULL, 0, NULL, '2010-12-09 21:50:46', 2.0, NULL, '2010-12-09', 1, NULL, 1, NULL, NULL)
 from /home/cmatthews/src/cannon/vendor/rails/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb:219:in `log'
 from /home/cmatthews/src/cannon/vendor/rails/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb:319:in `execute'
 from /home/cmatthews/src/cannon/vendor/rails/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb:259:in `insert_sql'
 from /home/cmatthews/src/cannon/vendor/rails/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb:329:in `insert_sql'
 from /home/cmatthews/src/cannon/vendor/rails/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb:44:in `insert_without_query_dirty'
 from /home/cmatthews/src/cannon/vendor/rails/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb:18:in `insert'
 from /home/cmatthews/src/cannon/vendor/rails/activerecord/lib/active_record/base.rb:2901:in `create_without_timestamps'
 from /home/cmatthews/src/cannon/vendor/rails/activerecord/lib/active_record/timestamp.rb:53:in `create_without_callbacks'
 from /home/cmatthews/src/cannon/vendor/rails/activerecord/lib/active_record/callbacks.rb:266:in `create'
 from /home/cmatthews/src/cannon/vendor/rails/activerecord/lib/active_record/base.rb:2867:in `create_or_update_without_callbacks'
 from /home/cmatthews/src/cannon/vendor/rails/activerecord/lib/active_record/callbacks.rb:250:in `create_or_update'
 from /home/cmatthews/src/cannon/vendor/rails/activerecord/lib/active_record/base.rb:2538:in `save_without_validation'
 from /home/cmatthews/src/cannon/vendor/rails/activerecord/lib/active_record/validations.rb:1078:in `save_without_dirty'
 from /home/cmatthews/src/cannon/vendor/rails/activerecord/lib/active_record/dirty.rb:79:in `save_without_transactions'
 from /home/cmatthews/src/cannon/vendor/rails/activerecord/lib/active_record/transactions.rb:229:in `send'
 from /home/cmatthews/src/cannon/vendor/rails/activerecord/lib/active_record/transactions.rb:229:in `with_transaction_returning_status'
 from /home/cmatthews/src/cannon/vendor/rails/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb:136:in `transaction'
 from /home/cmatthews/src/cannon/vendor/rails/activerecord/lib/active_record/transactions.rb:182:in `transaction'
 from /home/cmatthews/src/cannon/vendor/rails/activerecord/lib/active_record/transactions.rb:228:in `with_transaction_returning_status'
 from /home/cmatthews/src/cannon/vendor/rails/activerecord/lib/active_record/transactions.rb:196:in `save'
 from /home/cmatthews/src/cannon/vendor/rails/activerecord/lib/active_record/transactions.rb:208:in `rollback_active_record_state!'
 from /home/cmatthews/src/cannon/vendor/rails/activerecord/lib/active_record/transactions.rb:196:in `save'


0 commentaires

3 Réponses :


1
votes

Pouvez-vous modifier la requête en xxx

, vous pouvez envisager insérer ... sur la mise à jour de la touche en double ... .

L'insertion La documentation est Ici .


1 commentaires

Je pense que cela résoudrait quelque peu le problème, mais la requête SQL est générée automatiquement. Je pourrais le modifier, sauf que je veux que cela augmente une erreur, je ne peux qu'un que je puisse attraper et avoir un message, cela rend simplement le serveur dire 500 erreurs de serveur interne.



4
votes

Vous pouvez ajouter une contrainte d'unicité à votre modèle afin que l'enregistrement revienne avec des erreurs et que ce soit invalide.

Par exemple (Rails 2): P>

user1 = User.create :email => "one@example.com", :name => "one", :age => 20
user2 = User.create :email => "one@example.com", :name => "one", :age => 20
user2.valid? # false


4 commentaires

Je sais que je peux le faire pour un seul champ, mais puis-je le faire pour plusieurs comme dans la mesure de possible, je peux vérifier si elles ont la même chose: email, nom, couleur préférée et travail. Il peut y avoir 5 personnes nommées John, mais un seul peut avoir john@example.com, orange et être programmeur. Cela a-t-il du sens?


Hé, j'ai mis à jour le message avec la réponse pour plusieurs attributs.


Bien que cela couvre la plupart des cas d'utilisation, il y a et a toujours été une condition de race dans Validates_uniqueness_of - elle n'arrête pas complètement les entrées en double grâce à la manière dont cela fonctionne.


C'est correct omar. Vous devriez toujours avoir un index unique dans MySQL sur (nom, âge, email) et il est préférable d'entourer vos mises à jour avec COMMEND..RESCUE..END.



17
votes
begin
  Event.create!(:name => 'Ironman Lanzarote 2011')
rescue ActiveRecord::RecordNotUnique => e
  # handle duplicate entry 
end
This works for me under Rails 3.

3 commentaires

Cela viole le principe du moindre étonnement et ne suit pas les conventions dans les rails.


Lorsque vous utilisez une configuration maître / esclave, vous rencontrerez des problèmes de dérivation (et les conditions de course résultantes), qui peuvent facilement être résolues à l'aide de cette approche, au lieu d'utiliser la validation unique des rails, ce qui pourrait le vérifier sur l'esclave.


C'est bon, mais je mettrais ce comportement sur une méthode modèle avec un nom descriptif.