2009-09-26 10 views
49

The uniqueness validator of ActiveRecord ha un'opzione per saltare la convalida se il valore è nullo o vuoto. Anche se imposto entrambi i parametri su true (comportamento predefinito), posso creare un record con zero e vuoto prima che la convalida abbia esito positivo. Uso il database SQlite3 predefinito sqlite3-ruby (1.2.5).validates_uniqueness_of passa a zero o vuoto (senza allow_nil e allow_blank)

Modifica per chiarimenti: ottengo il risultato previsto se aggiungo validates_presence_of al modello. Ho pensato che il comportamento predefinito di validates_uniqueness_of avrebbe reso questo ridondante.

Testcase:

rails validation_test 
cd validation_test/ 
script/generate Model Thing identification:string 
rake db:migrate 

Contenuto delle app/modelli/thing.rb:

class Thing < ActiveRecord::Base 
    validates_uniqueness_of :identification 
end 

Rails console:

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 

Perché passano le prime due creazioni?

Grazie

+1

+1 perché questo è un modello di come fare una domanda. Hai affermato chiaramente cosa hai fatto, cosa hai visto e cosa ti aspettavi. – jdl

+0

Grazie. Ma sembra che questo non impedisca di essere frainteso. :) – Roman

risposta

89

Si è confuso con il comportamento predefinito. Da the 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). 

impostazione sia di quelli al vero, vedo il seguente comportamento con 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: Affrontare il vostro chiarimento. Aggiungere un validates_presence_of sarebbe corretto per quello che stai cercando di fare. Non è ridondante, dal momento che sta verificando un caso di errore completamente diverso. Ha anche il proprio messaggio di errore, che sarà importante per l'utente.

class Thing < ActiveRecord::Base 
    validates_uniqueness_of :identification, :allow_nil => true, :allow_blank => true 
    validates_presence_of :identification 
end 
+0

In realtà lo voglio al contrario. Voglio evitare completamente i valori nulli e vuoti. Come un ulteriore validates_presence_of farebbe. Ma pensavo che la validates_presence sarebbe ridondante se c'è già un validates_unquality_of validator. – Roman

+0

Ok ora questo ha senso. Anche un nulla e un vuoto possono infatti essere unici. Se voglio evitare valori vuoti, devo dire esplicitamente questo. Prima ho trovato irritante. Ora, ripensandoci, mi piace ancora di più in questo modo. Penso di aver appena fatto un altro piccolo passo nella giusta direzione. Grazie. – Roman

+9

': allow_blank => true' include valori nulli. Quindi un ulteriore ': allow_nil => true' è ridondante. – wdspkr

Problemi correlati