73

如果值为 nil 或空白,ActiveRecord 的唯一性验证器具有跳过验证的选项。即使我将两个参数都设置为 true (默认行为),我也可以在验证命中之前创建一个带有 nil 和空白的记录。我使用默认的 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

导轨控制台:

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

为什么前两个创作通过了?

谢谢

4

3 回答 3

125

您对默认行为有误。从文档

:allow_nil- 如果设置为 true,则在属性为 nil 时跳过此验证(默认为 false)。 :allow_blank- 如果设置为 true,则在属性为空白时跳过此验证(默认为 false,它也包括 nil)。

设置allow_blank为 true,我看到 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">

编辑:解决您的澄清问题。

添加 avalidates_presence_of对于您要执行的操作是正确的。这不是多余的,因为它正在检查一个完全不同的错误情况。它还有自己的错误消息,这对用户很重要。

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

并与validates

validates :email, uniqueness: { allow_blank: true }
# or
validates :email, uniqueness: { allow_nil: true }
于 2020-08-17T16:13:41.800 回答
0
class Thing < ActiveRecord::Base
  validates :identification, uniqueness: true, allow_nil: true
end
于 2021-11-02T20:04:10.373 回答