73

ActiveRecord の一意性バリデーターには、値が nil または空白の場合に検証をスキップするオプションがあります。両方のパラメーターを true (デフォルトの動作) に設定しても、検証がヒットする前に、nil と空白で 1 つのレコードを作成できます。デフォルトの SQLite3 データベース sqlite3-ruby (1.2.5) を使用します。

明確にするために編集:validates_presence_ofモデルに追加すると、期待される結果が得られます。validates_uniqueness_ofのデフォルトの動作により、これが冗長になると思いました。

テストケース:

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

app/models/thing.rb の内容:

class Thing < ActiveRecord::Base
  validates_uniqueness_of :identification
end

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

最初の 2 つの作品が合格するのはなぜですか?

ありがとう

4

3 に答える 3

125

デフォルトの動作について間違っています。ドキュメントから:

:allow_nil- true に設定すると、属性が nil の場合にこの検証をスキップします (デフォルトは false)。 :allow_blank- true に設定すると、属性が空白の場合にこの検証をスキップします (デフォルトは false で、nil も含まれます)。

true に設定allow_blankすると、Rails 2.3.4 で次のような動作が見られます。

class Thing < ActiveRecord::Base
  validates_uniqueness_of :identification, :allow_blank => 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">

編集:あなたの明確化に対処します。

を追加するvalidates_presence_ofことは、あなたがやろうとしていることに対して正しいでしょう。まったく異なるエラーケースをチェックしているため、冗長ではありません。また、ユーザーにとって重要な独自のエラー メッセージもあります。

class Thing < ActiveRecord::Base
  validates_uniqueness_of :identification, :allow_blank => true
  validates_presence_of :identification
end
于 2009-09-26T03:11:19.380 に答える