15.4 Validation
1、validates_acceptance_of 确认checkbox是否被标记
2、validates_associated 在关联的对象上完成确认。
3、validates_confirmation_of 确认字段和它的值有同样内容
4、validates_each 使用一个块来确认一或多个属性
5、validates_exclusion_of 确认属性不在一组值中。
6、validates_format_of 在一个模式上确认属性。
7、validates_inclusion_of 确认属性是否属于一个值集。
8、validates_length_of 确认属性值的长度。
9、validates_numericality_of 确认那个属性是有效的数字
10、validates_presence_of 确认属性不为空。
11、validates_uniqueness_of 确认属性是唯一的。
“活动记录”可以确认一个“模型”对象的内容。这个确认在一个对象被保存时可以自动地完成。你也可以编程请求一个“模型”的当前状态的确认。
就像我们在上一章提到的,“活动记录”能够区别出数据库内与现有行相应的“模型”还是没有现有行与之对应的“模型”。后者被称为新记录(new_record?()方法将为它们返回true)。当你调用save()方法时,“活动记录”将为新记录完成一个SQL 插入操作并对现有的那个进行更新。
这种区别是“活动记录”的确认工作流的反射—你可以指定在所有保存操作上完成的确认,以及只用于创建或更新上完成的确认。
在低层你通过实现validate( ), validate_on_create( ), 和 validate_on_update( )这些方法的一个或多个来指定确认。validate()方法在每个保存操作中被调用。后两个则依赖于记录是否是新的,或者它先前是否从数据库中读取过来调用。
除了调用valid?()保存“模型”对象到数据外,你也可以在任何时候运行确认。这个调用与调用save()来保存的两个确认方法是一样的。
class User < ActiveRecord::Base
def validate
unless name && name =~ /^w+$/
errors.add(:name, "is missing or invalid")
end
end
def validate_on_create
if self.find_by_name(name)
errors.add(:name, "is already being used")
end
end
end
当一个确认方法发现问题时,它使用errors.add()方法添加一个信息给这个“模型”对象的错误列表。第一个参数是出错属性的名字,第二个参数是错误消息。如果你需要添加一个用于整个“模型”对象的错误消息,使用add_to_base()方法代替。(注意,这个代码使用了支持方法blank?(),它在它的被调为nil或是个空字符串时返回true。)
def validate
if name.blank? && email.blank?
errors.add_to_base("You must specify a name or an email address")
end
end
像我们353页看到的,Rails“视图”在显示表单给最终用户时可以使用错误列表—有错误的字段将被自动高亮度地显示,并且用错误列表添加一个漂亮的方框在顶部。
你可以编程为一个特定属性使用errors.on(:name)(别名为errors[:name])来获得错误,并且你可以用errors.clear()清除整个错误列表。如果你查阅ActiveRecord::Errors文档,你会发现有很多其它方法。大多数方法可由高级的确认帮助方法来代替。
Validation Helpers
有些确认是平常:这个属性必须不能为空,其它属性必须在18和65之间等等。“活动记录”有一套标准的帮助方法来添加这些确认给你的“模型”。每个都是类级别方法,所有名字都以validates_开头。每个方法接受可选的属性名字列表,它是由配置选项的哈希表提供给确认的。
例如,我们可以这样写先前确认
class User < ActiveRecord::Base
validates_format_of :name,
:with => /^w+$/,
:message => "is missing or invalid"
validates_uniqueness_of :name,
:on => :create,
:message => "is already being used"
end
大多数validates_methods接受:on和:message选项。:on选项确定何时应用确认并接受:save(缺省的),:create,或:update中的一个。:message参数可以用生成错误消息覆写它。
确认失败时,帮助方法添加一个error对象给“活动记录”“模型”对象。这将被关联到被确认的字段。在确认之后,你可以查看“模型”对象的errors属性来访问错误列表。当“活动记录”被用做Rails应用程序一部分时,这个检查通常由两个步骤完成:
1、“控制器”试图保存一个“活动记录”对象,但因为确认的原因保存失败了 (返回false)。 “控制器”将重新显示包含错误数据的表单。
2、“视图模板”使用error_messages_for()方法来显示“模型”对象的错误列表,并且用户有机会来修正字段。
我们在17.8节讨论表单与“模型”的交互。
这儿是你可以用在“模型”对象内的确认帮助方法的清单:
1、validates_acceptance_of 确认checkbox是否被标记。
validates_acceptance_of attr... [ options... ]
许多表单有checkbox,用户必须选择以便接受一些条款或条件。这个确认简单地检验这个box已经确认被标记,这个属性值是个字符串。属性本身并不被保存在数据库内(如果你希望明确地记录确认的话,没有什么东西会阻止你这样做)。
class Order < ActiveRecord::Base
validates_acceptance_of :terms,
:message => "Please accept the terms to proceed"
end
选项:
:message text,缺省是“must be accepted.”。
:on :save,:create 或者:update
2、validates_associated 在关联的对象上完成确认。
validates_associated name... [ options... ]
在给定的属性上完成确认,它被假设为是“活动记录模型”。对每个与属性关联的确认失败的话,一个单独的消息将被添加到那个属性的错误列表中(也就是说,个别的细节原因而出现的失败,将不会写到“模型”的错误列表中)。
小心不要包含一个validates_associated()调用在彼此引用的“模型”中:第一个将会试图确认第二个,它依次将确认第一个等等,直接你堆栈溢出。
class Order < ActiveRecord::Base
has_many :line_items
belongs_to :user
validates_associated :line_items,
:message => "are messed up"
validates_associated :user
end
选项:
:message text ,缺省是 “is invalid.”
:on :save,:create 或者:update
3、validates_confirmation_of 确认字段和它的值有同样内容。
validates_confirmation_of attr... [ options... ]
很多表单要求用户输入同一信息两次,第二次拷贝“动作”被做为与第一次是否匹配的确认。如果你使用命名约定,即第二字段的名字附有_confirmation,你可以使用validates_confirmation_of()来检查两个字段是否有同样的值。第二个字段不需要被存储到数据库中。
例如,一个“视图”可能包含
<%= password_field "user", "password" %><br />
<%= password_field "user", "password_confirmation" %><br />
在User“模型”中,你可以用一个确认来检验两个口令。
class User < ActiveRecord::Base
validates_confirmation_of :password
end
选项:
:message text 缺省是“doesn’t match confirmation.”
:on :save, :create, 或 :update
4、validates_each 使用一个块来确认一或多个属性。
validates_each attr... [ options... ] { |model, attr, value| ... }
为每个属性调用块(如果:allow_nil为true,则跳过是nil的属性)。传递属性的名字,属性的值到被确认的“模型”内。如下面例子显示的,如果一个确认失败,块应该被添加给“模型”的错误列表
class User < ActiveRecord::Base
validates_each :name, :email do |model, attr, value|
if value =~ /groucho|harpo|chico/i
model.errors.add(attr, "You can't be serious, #{value}")
end
end
end
选项:
:allow_nil boolean 如果 :allow_nil 为 true,带有值nil的属性将不被传递给块而是被跳过。
:on :save, :create, 或 :update
5、validates_exclusion_of 确认属性不在一组值中。
validates_exclusion_of attr..., :in => enum [ options... ]
确认属性没有出现在枚举中(任何对象都支持include?()断言)。
class User < ActiveRecord::Base
validates_exclusion_of :genre,
:in => %w{ polka twostep foxtrot },
:message => "no wild music allowed"
validates_exclusion_of :age,
:in => 13..19,
:message => "cannot be a teenager"
end
选项:
:allow_nil 如果属性为nil,并且:allow_nil选项为true。则枚举不被检查。
:in (或 :within) enumerable 一个可枚举对象。
:message text 缺省值是 “is not included in the list.”
:on :save, :create, 或 :update
6、validates_format_of 在一个模式上确认属性。
validates_format_of attr..., :with => regexp [ options... ]
通过与正则表达式匹配它的值来确认每个字段。
class User < ActiveRecord::Base
validates_format_of :length, :with => /^d+(in|cm)/
end
选项:
:message text 缺省值 “is invalid.”
:on :save, :create, or :update
:with 用于确认属性的正则表达式。
7、validates_inclusion_of 确认属性是否属于一个值集。
validates_inclusion_of attr..., :in => enum [ options... ]
确认每个属性的值是否出现在枚举中(任何对象都支持include?()断言)。
class User < ActiveRecord::Base
validates_inclusion_of :gender,
:in => %w{ male female },
:message => "should be 'male' or 'female'"
validates_inclusion_of :age,
:in => 0..130,
:message => "should be between 0 and 130"
end
选项:
:allow_nil 如果属性为nul并且:allow_nil选项为true,则不检查枚举值。
:in (或 :within) enumerable 一个可枚举的对象。
:message text 缺省值是 “is not included in the list.”
:on :save, :create, 或 :update
8、validates_length_of 确认属性值的长度。
validates_length_of attr..., [ options... ]
遵循一些约束确认每个属性的值的长度:至少要给出一个长度,至多给出一个长度,在两个长度之间,或者明确地给出一个长度。而不能只有单个:message选项,这个确认器允许为不同的确认失败分离消息,只要:message还可以使用。在所有选项中,长度不能负数。
class User < ActiveRecord::Base
validates_length_of :name, :maximum => 50
validates_length_of :password, :in => 6..20
validates_length_of :address, :minimum => 10,
:message => "seems too short"
end
选项(用于validates_length_of):
:in (或 :within) range 值的长度必须在一个范围内。
:is integer 值必须是整数的字符长度。
:minimum integer 值不能小于此整数。
:maximum integer 值不能大于此整数。
:message text 依赖于完成测试的缺省信息。消息可以包含一个将被maximun,minimum,或确定长度代替的%d序列。
:on :save, :create, 或 :update
:too_long text 使用:maximum时的:message同义词。
:too_short text使用:minimum时的:message同义词。
:wrong_length text使用:is 时的:message同义词。
9、validates_numericality_of 确认那个属性是有效的数字。
validates_numericality_of attr... [ options... ]
确认每个属性是个有效数字。在:only_integer选项中,属性必须由可选的符号后跟随一个或多个数字。在选项中(或者如果选项不是true),可由Ruby Float()方法允许的任何浮点数都被接受。
class User < ActiveRecord::Base
validates_numericality_of :height_in_meters
validates_numericality_of :age,
nly_integer => true
end
选项:
:message text 缺省是 “is not a number.”
:on :save, :create, 或 :update
:only_integer 如果为 true,则属性必须是包含一个可选的符号后跟随数字的字符串。
10、validates_presence_of 确认属性不为空。
validates_presence_of attr... [ options... ]
确认每个属性即不为nil也不为空。
class User < ActiveRecord::Base
validates_presence_of :name, :address
end
选项:
:message text 缺省是 “can’t be empty.”
:on :save, :create, 或 :update
11、validates_uniqueness_of 确认属性是唯一的。
validates_uniqueness_of attr... [ options... ]
对于每个属性,确认数据库内的其它行当前没有与给定列同样的值。当“模型”对象来自于一个现有数据库的行时,当完成检查时那个行被忽略。选项:scope参数可以被用于过滤当前记录内:scope列内被测试的,有同样值的行。
这个代码确保用户名字在数据库中唯一的。
class User < ActiveRecord::Base
validates_uniqueness_of :name
end
这个代码确保用户的名字在一个组内唯一的。
class User < ActiveRecord::Base
validates_uniqueness_of :name, :scope => "group_id"
end
选项:
:message text 缺省是 “has already been taken.”
:on :save, :create, 或 :update
:scope attr Limits the check to rows having the same value in the column as the row being checked.