2009-09-26 4 views
49

The uniqueness validator of ActiveRecord verfügt über Optionen zum Überspringen der Validierung, wenn der Wert null oder leer ist. Auch wenn ich beide Parameter auf "true" (das Standardverhalten) setze, kann ich einen Datensatz mit nil und leer erstellen, bevor die Validierung eintritt. Ich benutze die Standard-SQlite3-Datenbank sqlite3-ruby (1.2.5).validates_uniqueness_of übergibt null oder leer (ohne allow_nil und allow_blank)

Zur Klarstellung bearbeiten: Ich bekomme das erwartete Ergebnis, wenn ich validates_presence_of zum Modell hinzufügen. Ich dachte, dass das Standardverhalten von validates_uniqueness_of dies überflüssig machen würde.

Testfall:

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

Inhalt von app/models/thing.rb:

class Thing < ActiveRecord::Base 
    validates_uniqueness_of :identification 
end 

Rails-Konsole:

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 

Warum die ersten beiden Kreationen passieren?

Danke

+1

+1, weil dies ein Modell ist, wie man eine Frage stellt. Du hast klar gesagt, was du getan hast, was du gesehen hast und was du erwartet hast. – jdl

+0

Danke. Aber es scheint, dass dies nicht daran hindert, missverstanden zu werden. :) – Roman

Antwort

89

Sie irren sich über das Standardverhalten. Von 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). 

beide von denen auf true setzen, sehe ich das folgende Verhalten mit 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"> 

Bearbeiten: Adressierung Ihrer Klarstellung. Eine validates_presence_of hinzufügen würde für das, was Sie versuchen, richtig sein. Es ist nicht redundant, da es nach einem völlig anderen Fehlerfall sucht. Es hat auch eine eigene Fehlermeldung, die für den Benutzer wichtig ist.

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

Eigentlich will ich es anders herum. Ich möchte Null und leere Werte vollständig verhindern. Wie eine zusätzliche validates_presence_of tun würde. Aber ich dachte, die validates_presence wäre redundant, wenn es bereits einen validates_uniqueness_of validator gibt. – Roman

+0

Okay, jetzt macht das Sinn. Sogar ein Null- und Leerwert kann tatsächlich einzigartig sein. Wenn ich leere Werte verhindern möchte, muss ich das explizit sagen. Zuerst fand ich es irritierend. Jetzt, bei einem zweiten Gedanken, mag ich es sogar mehr so. Ich denke, ich habe gerade einen weiteren kleinen Schritt in die richtige Richtung gemacht. Vielen Dank. – Roman

+9

': allow_blank => true' enthält keine Werte. Also ist ein zusätzliches ': allow_nil => true' überflüssig. – wdspkr

Verwandte Themen