2 Validation Helpers 校验辅助方法
2.1 acceptance 接受
class
Person < ActiveRecord::Base
validates
:terms_of_service
, acceptance:
true
end
|
这个helper 默认的错误信息是 "must be accepted".
它能收到一个 :accept 属性, 来决定所想要的接受值. 默认是"1", 更改起来也容易.
class
Person < ActiveRecord::Base
validates
:terms_of_service
, acceptance: { accept:
'yes'
}
end
|
2.2 validates_associated 关联校验
class
Library < ActiveRecord::Base
has_many
:books
validates_associated
:books
end
|
这个校验将会对于所有的关联类型都会起作用.
warning: 不要对于你的关联对象两端都使用 validates_associated. 他们将会陷入互相调用的无限循环.
对于 validates_associated 的默认错误信息是 "is invalid". 注意, 每一个被关联的对象都包含各自的 errors 集合, errors 不会在调用模型时冒出来.
2.3 confirmation 确认
class
Person < ActiveRecord::Base
validates
:email
, confirmation:
true
end
|
在你的视图模板中, 你可以这样使用:
<%=
text_field
:person
,
:email
%>
<%=
text_field
:person
,
:email_confirmation
%>
|
这个校验只有当 email_confirmation 不为 nil时, 才会被执行. 为了声明必须要确认, 确定要增加一个对于确认特性的 presence 检查(我们将会在后面详细了解 presence).
class
Person < ActiveRecord::Base
validates
:email
, confirmation:
true
validates
:email_confirmation
, presence:
true
end
|
对于这个 helper 的默认错误信息是 "doesn't match confirmation".
2.4 exclusion 不包括
class
Account < ActiveRecord::Base
validates
:subdomain
, exclusion: {
in
: %w(www us ca jp),
message:
"%{value} is reserved."
}
end
|
这个 exclusion helper 有一个属性 :in, 接收一些值的集合, 这些值将不会被校验的特性所接收. :in 属性有一个别名叫作 :within, 你可以用来表示相同的作用目的, 如果你乐意这样做的话. 这个例子使用的 :message 属性是用来显示, 你如何能够包括特性的值.
默认的错误信息是 "is reserved".
2.5 format 格式
class
Product < ActiveRecord::Base
validates
:legacy_code
, format: { with: /\
A
[a-zA-
Z
]+\z/,
message:
"only allows letters"
}
end
|
默认的错误信息是 "is invalid".
2.6 inclusion 包含
class
Coffee < ActiveRecord::Base
validates
:size
, inclusion: {
in
: %w(small medium large),
message:
"%{value} is not a valid size"
}
end
|
这个 inclusion helper 有一个属性 :in, 接收的一些值的集合是被接受的.
2.7 length 长度
class
Person < ActiveRecord::Base
validates
:name
, length: { minimum:
2
}
validates
:bio
, length: { maximum:
500
}
validates
:password
, length: {
in
:
6
..
20
}
validates
:registration_number
, length: { is:
6
}
end
|
这些长度方面可用的限制属性是:
- :minimum -- 属性不能够小于它所声明的长度.
- :maximum -- 属性不能够大于它所声明的长度.
- :in(or within) -- 属性长度必须被包含在这个间隔内. 这个值必须是一个区间.
- :is -- 属性长度必须是这个值相等.
默认的错误信息是依赖于长度校验的类型所决定的. 你能够定制化这些信息, 通过使用 :wrong_length, :too_long, 和 too_short 属性, 以及 %{count} 作为一个占位符用来对应于所设置长度的数字. 你也能够使用 :message 属性来声明错误信息.
class
Person < ActiveRecord::Base
validates
:bio
, length: { maximum:
1000
,
too_long:
"%{count} characters is the maximum allowed"
}
end
|
这个 helper 默认统计字符数, 但你能够用不同的方式来分割这个值, 通过使用 :tokenizer 属性:
class
Essay < ActiveRecord::Base
validates
:content
, length: {
minimum:
300
,
maximum:
400
,
tokenizer: lambda { |str| str.scan(/\w+/) },
too_short:
"must have at least %{count} words"
,
too_long:
"must have at most %{count} words"
}
end
|
注意, 默认的错误信息是复数的(e.g. "is too short (minimum is %{count} characters)"). 正是这个原因, 当 :minimum 是1时, 你应该提供一个个性化的消息, 或者用 presence: true 来替代. 当 :in 或者 :within 有低于1时, 你应该要么提供个性化的消息, 要么优先效用 presence.
2.8 numericality 数字化
/\
A
[+-]?\d+\
Z
/
|
正则表达式会去校验属性的值. 否则的话, 它会尝试把这个值转换成一个浮点数.
warning: 注意, 上面的正则表达式允许后面新的一行字符.
class
Player < ActiveRecord::Base
validates
:points
, numericality:
true
validates
:games_played
, numericality: { only_integer:
true
}
end
|
除了 :only_integer, 这个 helper 也接受下面的属性, 来限制所接受的值:
:greater_than -- 声明的值必须大于所提供的值, 这个属性默认的错误信息是"must be greater than %{count}".
:greater_than_or_equal_to -- 声明的值必须大于或等于所提供的值. 这个属性默认的错误信息是 "must be greater than or equal to %{count}”
:equal_to — 声明的值必须等于所提供的值。这个属性默认的错误消息是 “must be less equal to %{count}”.
:less_than — 声明的值必须小于所提供的值。这个属性默认错误信息是 “must be less than %{count}”.
:less_than_or_equal_to — 声明的值必须小于等于所提供的值。这个属性默认错误信息 “must be less than or equal to %{count}”.
:odd — 如果设置成true,声明的值必须是一个奇数。这个属性默认的错误信息是 “must be odd”.
:even — 如果设置成true,声明的值必须是一个偶数。这个属性默认的错误信息是 “must be even”.
默认的错误信息是 "is not a number”.
2.9 presence 存在
class
Person < ActiveRecord::Base
validates
:name
,
:login
,
:email
, presence:
true
end
|
如果你能确定的是,一个关联性是存在的,你将会需要去测试所关联的对象本身是否是存在的,没有外键被用来映射这关联性。
class
LineItem < ActiveRecord::Base
belongs_to
:order
validates
:order
, presence:
true
end
|
为了去校验所关联的记录,其存在性是必须的,你必须声明 :inverse_of 属性为了关联性:
class
Order < ActiveRecord::Base
has_many
:line_items
, inverse_of:
:order
end
|
如果你校验一个被关联对象的存在性,通过一个 has_one 或者 has_many 关联,它会检查这个对象既不是 blank? 又不是 marked_for_destruction?.
既然 false.blank? 是 true,如果你想要校验 boolean 字段的存在性,你应该使用 validates :field_name, inclusion: { in: [true, false] }.
默认的错误信息是 “can’t be blank”.
2.10 absence 缺席
class
Person < ActiveRecord::Base
validates
:name
,
:login
,
:email
, absence:
true
end
|
如果你想要确认一个关联性是缺失的,你将会需要去测试该关联性本身是否是缺失的,没有外键被用来映射其关联性。
class
LineItem < ActiveRecord::Base
belongs_to
:order
validates
:order
, absence:
true
end
|
为了去校验所关联的记录,其缺失性是必学的,你必须为了这个关联性而要声明 :inverse_of 属性:
class
Order < ActiveRecord::Base
has_many
:line_items
, inverse_of:
:order
end
|
如果你校验所关联对象的缺失性,通过一个 has_one 或者 has_many 来关联,它会检查该对象既不是 present? 也不是 maked_for_destruction?.
既然 false.present? 是 false,如果你想要校验一个boolean 字段的缺失性,你应该使用 validates :field_name, exclusion: { in:[true, false]}.
默认的错误信息是“must be blank”.
2.11 uniqueness 唯一性
class
Account < ActiveRecord::Base
validates
:email
, uniqueness:
true
end
|
这校验发生在模型的数据表里执行一个SQL查询时,在那个属性用相同的值查询一个已经存在的记录。
class
Holiday < ActiveRecord::Base
validates
:name
, uniqueness: { scope:
:year
,
message:
"should happen once per year"
}
end
|
也有一个 :case_sensitive 属性,你能够用来定义,唯一性限制对于大小写是否敏感。这个属性默认是 true。
class
Person < ActiveRecord::Base
validates
:name
, uniqueness: { case_sensitive:
false
}
end
|
2.12 validates_with 校验
class
GoodnessValidator < ActiveModel::Validator
def
validate(record)
if
record.first_name ==
"Evil"
record.errors[
:base
] <<
"This person is evil"
end
end
end
class
Person < ActiveRecord::Base
validates_with GoodnessValidator
end
|
class
GoodnessValidator < ActiveModel::Validator
def
validate(record)
if
options[
:fields
].any?{|field| record.send(field) ==
"Evil"
}
record.errors[
:base
] <<
"This person is evil"
end
end
end
class
Person < ActiveRecord::Base
validates_with GoodnessValidator, fields: [
:first_name
,
:last_name
]
end
|
注意, 校验对象在整个应用生命周期中只会被初始化一次, 而不是在每一次的校验执行时, 因此在其内部要仔细地使用实例变量.
如果你的校验是足够的复杂, 你想要一些实例变量, 你可以简单地使用一个简洁的老旧的Ruby对象来替代:
class
Person < ActiveRecord::Base
validate
do
|person|
GoodnessValidator.
new
(person).validate
end
end
class
GoodnessValidator
def
initialize(person)
@person
= person
end
def
validate
if
some_complex_condition_involving_ivars_and_private_methods?
@person
.errors[
:base
] <<
"This person is evil"
end
end
# ...
end
|
2.13 validates_each 校验
class
Person < ActiveRecord::Base
validates_each
:name
,
:surname
do
|record, attr, value|
record.errors.add(attr,
'must start with upper case'
)
if
value =~ /\
A
[a-z]/
end
end
|
这个代码块接收到数据记录行, 属性的名称和属性值. 在代码块中你可以做任何你想做的校验. 如果你的校验失败了, 你应该增加一个错误消息到模型中, 因此使它无效.