Le validateur d'unicité d'ActiveRecord a une option pour ignorer la validation si la valeur est nulle ou vide. Même si j'ai défini les deux paramètres sur true (le comportement par défaut), je peux créer un enregistrement avec nil et vide avant que la validation ne frappe. J'utilise la base de données SQlite3 par défaut sqlite3-Ruby (1.2.5).
Modifier pour clarification: j'obtiens le résultat escompté si j'ajoute validates_presence_of
au modèle. Je pensais que le comportement par défaut de validates_uniqueness_of
rendrait cela superflu.
Cas de test:
Rails validation_test
cd validation_test/
script/generate Model Thing identification:string
rake db:migrate
Contenu de l'application/modèles/thing.rb:
class Thing < ActiveRecord::Base
validates_uniqueness_of :identification
end
Console Rails:
script/console
Loading development environment (Rails 2.3.4)
>> Thing.create!
=> #<Thing id: 1, identification: nil, created_at: "2009-09-26 01:49:32", updated_at: "2009-09-26 01:49:32">
>> Thing.create! :identification => ""
=> #<Thing id: 2, identification: "", created_at: "2009-09-26 01:49:42", updated_at: "2009-09-26 01:49:42">
>> Thing.create! :identification => ""
ActiveRecord::RecordInvalid: Validation failed: Identification has already been taken
from /usr/lib/Ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/validations.rb:1090:in `save_without_dirty!'
from /usr/lib/Ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/dirty.rb:87:in `save_without_transactions!'
from /usr/lib/Ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/transactions.rb:200:in `save!'
from /usr/lib/Ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/connection_adapters/abstract/database_statements.rb:136:in `transaction'
from /usr/lib/Ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/transactions.rb:182:in `transaction'
from /usr/lib/Ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/transactions.rb:200:in `save!'
from /usr/lib/Ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/transactions.rb:208:in `rollback_active_record_state!'
from /usr/lib/Ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/transactions.rb:200:in `save!'
from /usr/lib/Ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/validations.rb:1059:in `create!'
from (irb):3
>> Thing.count
=> 2
Pourquoi les deux premières créations passent-elles?
Merci
Vous vous trompez sur le comportement par défaut. De les docs :
:allow_nil - If set to true, skips this validation if the attribute is nil (default is false).
:allow_blank - If set to true, skips this validation if the attribute is blank (default is false).
En définissant les deux sur true, je vois le comportement suivant avec Rails 2.3.4.
class Thing < ActiveRecord::Base
validates_uniqueness_of :identification, :allow_blank => true, :allow_nil => true
end
>> Thing.create! :identification => ""
=> #<Thing id: 6, identification: "", created_at: "2009-09-26 03:09:48", updated_at: "2009-09-26 03:09:48">
>> Thing.create! :identification => ""
=> #<Thing id: 7, identification: "", created_at: "2009-09-26 03:09:49", updated_at: "2009-09-26 03:09:49">
>> Thing.create! :identification => nil
=> #<Thing id: 8, identification: nil, created_at: "2009-09-26 03:09:52", updated_at: "2009-09-26 03:09:52">
>> Thing.create! :identification => nil
=> #<Thing id: 9, identification: nil, created_at: "2009-09-26 03:09:53", updated_at: "2009-09-26 03:09:53">
Edit: Répondre à votre clarification. Ajouter un validates_presence_of
serait correct pour ce que vous essayez de faire. Ce n'est pas redondant, car il vérifie un cas d'erreur complètement différent. Il a également son propre message d'erreur, qui sera important pour l'utilisateur.
class Thing < ActiveRecord::Base
validates_uniqueness_of :identification, :allow_nil => true, :allow_blank => true
validates_presence_of :identification
end