Ruby on rails 理解Rails验证:什么是允许的?

Ruby on rails 理解Rails验证:什么是允许的?,ruby-on-rails,Ruby On Rails,我是Rails的新手,找到了一个小片段来逐步验证存在性和唯一性:首先检查存在性,然后检查唯一性 validates :email, :presence => true, :allow_blank => true, :uniqueness => { :case_sensitive => false } 我对同时使用presence=>true和allow\u blank=>true感到有点困惑 如果不使用allow\u blank=>true将同时检查这两个规则,而不是逐

我是Rails的新手,找到了一个小片段来逐步验证存在性和唯一性:首先检查存在性,然后检查唯一性

validates :email, :presence => true, :allow_blank => true, :uniqueness => { :case_sensitive => false }
我对同时使用
presence=>true
allow\u blank=>true
感到有点困惑

如果不使用
allow\u blank=>true
将同时检查这两个规则,而不是逐步检查


为什么
allow\u blank=>true
会产生这种魔力?

您所得到的与此等价(为了清晰起见包装):

这有点傻,因为如果你需要在场,那么这将使:allow_blank子句对:university“无效”

validates :email, :presence => true, :allow_blank => true, :uniqueness => { :case_sensitive => false }
当您切换到使用其他验证器时,它更有意义。。说。。。格式和唯一性,但如果为空,则不需要任何检查。在这种情况下,添加一个“全局应用”:allow_blank更有意义,并使代码干涸一点

这个

validates :email, :format => {:allow_blank => true, ...}, 
                  :uniqueness => {:allow_blank => true, ...}
可以这样写:

validates :email, :allow_blank => true, :format => {...}, :uniqueness => {...}

:allow_blank
是一个选项,它将“禁用”多个验证器,但不会禁用状态验证器。将这两个字段一起使用的结果是,当字段留空时,您将得到
:blank
错误消息(即“不能为空”),但不会得到其他错误消息。

了解以下区别非常有用:

presence: true                    # nil and empty string fail validation
presence: true, allow_blank: true # nil fails validation, empty string passes
来自Rails注释

\*:allow#nil-如果属性为+nil+,则跳过验证。
#*:allow_blank-如果属性为空,则跳过验证。

因此,这意味着当我们在电子邮件上使用
允许空白
时,如果电子邮件为零,则只有一个错误添加到
errors
对象中,跳转唯一性验证。

在您的代码中,
:presence=>
:university=>
是验证程序,而
:allow_blank=>
是传递给其他验证器的默认选项

因此,您的代码:

验证(
:电邮,
:presence=>true,
:allow_blank=>true,
:唯一性=>{:区分大小写=>false}
)
等同于此代码:

验证(
:电邮,
:presence=>{:allow_blank=>true},
:university=>{:allow_blank=>true,:区分大小写=>false}
)
但是,
presence
验证器忽略了
allow\u blank
选项,因此您的代码基本上是这样的:

验证(
:电邮,
:presence=>{},#`{}`等同于'true'`
:university=>{:allow_blank=>true,:区分大小写=>false}
)
:university
中具有
:allow_blank=>true
意味着当电子邮件为空时,
university
验证将不会运行

这样做的一个效果是消除了DB查询

例如,如果没有
:allow_blank=>true
条件,您将看到:

>> user = User.new(email: nil)
>> user.valid?
  User Exists (0.2ms) SELECT  1 AS one FROM "users" WHERE "users"."name" IS NULL LIMIT 1
=> false
>> user.errors.messages
=> {:email=>["can't be blank"]}
但是使用
:allow_blank=>true
选项,您将不会看到
用户存在
数据库查询发生

当您的数据库中已有一个电子邮件地址为空的记录时,会发生另一种边缘情况的副作用。在这种情况下,如果您没有
唯一性
验证器上的
:allow_blank=>true
选项,那么您将看到返回两个错误:

>> user = User.new(email: nil)
>> user.valid?
  User Exists (0.2ms) SELECT  1 AS one FROM "users" WHERE "users"."name" IS NULL LIMIT 1
=> false
>> user.errors.messages
=> {:email=>["has already been taken", "can't be blank"]}

但是使用
:allow_blank=>true
选项,您只会看到
“can't be blank”
错误(因为当电子邮件为空时,唯一性验证将不会运行)。

在官方指南中说:“allow_blank被状态验证程序忽略”。这可能会有所帮助。另外,请查看一下,谢谢!我刚刚在stackoverflow上的某个地方发现了这段代码,并开始好奇为什么有人应该一起使用
allow_blank
presence
:)例如,您可能想一起使用它们来显示无效格式与空白格式的不同错误消息。如果不将allow_设置为空,则会得到一个空值的“无效格式”,这是真的吗?据我所知,allow_blank将跳过对所有空白值的验证
nil
为空值。Rails 5上的一个快速测试告诉我,
nil
不会使我的验证失败……这个答案是非常错误的!至少在Rails 5中。@dferrazm在这里是正确的,您可以通过查看带有
allow_blank
选项的状态验证程序的测试来查看:在代码中验证了
presence
allow_blank
如何协同工作的行为后,请编辑带有更正的答案。很多年前我就停止使用Rails了,否则我会自己做。我依靠社区来保持此答案的最新性和可靠性。要使此工作正常,请使用
validates:columnx,presence:true,if:Proc.new{x | x.columnx.nil}
,基于
>> user = User.new(email: nil)
>> user.valid?
  User Exists (0.2ms) SELECT  1 AS one FROM "users" WHERE "users"."name" IS NULL LIMIT 1
=> false
>> user.errors.messages
=> {:email=>["has already been taken", "can't be blank"]}