2009-09-26 14 views
49

The uniqueness validator of ActiveRecord ma takie opcje, aby pominąć sprawdzanie czy wartość jest zerowa lub pusta. Nawet jeśli ustawię oba parametry na true (zachowanie domyślne), mogę utworzyć jeden rekord z wartością zerową i pustą, zanim trafi poprawność. Używam domyślnej bazy danych SQlite3 sqlite3-ruby (1.2.5).validates_uniqueness_of przechodzi na zero lub puste (bez allow_nil i allow_blank)

Edycja dla wyjaśnienia: uzyskać oczekiwany rezultat, jeśli dodam validates_presence_of do modelu. Myślałem, że domyślne zachowanie validates_uniqueness_of uczyniłoby to zbędnym.

Test-obudowy:

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

Zawartość app/models/thing.rb:

konsola
class Thing < ActiveRecord::Base 
    validates_uniqueness_of :identification 
end 

szyn:

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 

Dlaczego pierwsze dwie kreacje przekazać?

Dzięki

+1

+1 ponieważ jest to model zadawania pytań. Jasno określiłeś, co zrobiłeś, co zobaczyłeś i czego się spodziewałeś. – jdl

+0

Dzięki. Wygląda jednak na to, że nie przeszkadza to w błędnym zrozumieniu. :) – Roman

Odpowiedz

89

Mylisz się z domyślnym zachowaniem. Od 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). 

Ustawienie obydwu tych true, widzę następujące zachowanie z 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"> 

Edytuj: Adresowanie wyjaśnienia. Dodanie validates_presence_of jest poprawne dla tego, co próbujesz zrobić. Nie jest zbędny, ponieważ sprawdza zupełnie inny przypadek błędu. Ma również własny komunikat o błędzie, który będzie ważny dla użytkownika.

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

Właściwie chcę to na odwrót. Chcę całkowicie uniknąć wartości zerowej i pustej. Tak, jak zrobiłaby to dodatkowa poprawka_wejściowa_. Ale myślałem, że validates_presence byłoby nadmiarowe, jeśli istnieje już validates_uniqueness_ validator. – Roman

+0

OK, teraz to ma sens. Nawet wartość zerowa i pusta może być w rzeczywistości wyjątkowa. Jeśli chcę zapobiec pustym wartościom, muszę to wyraźnie powiedzieć. Najpierw uznałem to za irytujące. Teraz, po namyśle, jeszcze bardziej lubię to w ten sposób. Myślę, że właśnie pomyślałem o kolejnym bardzo małym kroku we właściwym kierunku. Dzięki. – Roman

+9

': allow_blank => true' zawiera wartości zerowe. Tak więc dodatkowe ': allow_nil => true' jest zbędne. – wdspkr