`
jiajie0531
  • 浏览: 27542 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Active Record Validations 2 Validation Helpers 校验辅助方法

阅读更多
version: Rails 4.1

2 Validation Helpers 校验辅助方法

Active Record 提供了许多预定义的校验辅助方法(helpers), 你可以直接在你的类定义中使用. 这些辅助方法提供了一般性校验的规则. 每一次校验失败时, 一个错误信息被增加到对象的 errors 集合, 这个信息被关联到已被校验的属性.
 
每一个helper 接受属性名称的任意数量, 因此对于单独行的代码, 你可以对几个属性增加相同类型的校验.
 
他们都接受属性 :on 和 :message, 当校验被运行时定义上述属性, 当校验失败时, 把相应的错误信息增加到 errors 集合里. :on 属性获取的值是 :create 或者 :update. 对于每一个校验的 helpers 有默认的错误信息. 当 :message 属性没有被声明时, 这些信息会被使用. 让我们来分别看一下每一个可用的 helpers.
 

2.1 acceptance 接受

这个方法校验的是, 当一个 form 被提交的时候, 用户界面上的 checkbox 要被勾上. 这通常用于, 当用户同意你的应用服务协议的时候, 确认读到的文字, 或者类似的概念. 这个校验对于web应用是很著名的, 这个 'acceptance' 不需要被记录到你的数据库里(如果你没有为它设置字段, helper会创建一个虚拟的属性).
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 关联校验

你应该使用这个 helper, 当你的模型和其他的模型有关联的时候, 他们也需要被校验. 当你尝试去保存你的对象时, valid? 将会被紧接着调用, 涉及到所关联的对象.
class Library < ActiveRecord::Base
  has_many :books
  validates_associated :books
end

这个校验将会对于所有的关联类型都会起作用.

 

warning: 不要对于你的关联对象两端都使用 validates_associated. 他们将会陷入互相调用的无限循环.

 

对于 validates_associated 的默认错误信息是 "is invalid". 注意, 每一个被关联的对象都包含各自的 errors 集合, errors 不会在调用模型时冒出来.

 

2.3 confirmation 确认

你应该使用这个 helper, 当你有两个文本字段需要接受相同的内容时. 例如, 你可能想要确认一个 email 地址或者一个密码. 这个校验会创建一个虚拟的属性, 它的名字就是需要被确认字段的名字, 只是后面要加上"_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 不包括

这个 helper 校验的是, 属性的值没有被包括在所提供的集合中. 事实上, 这个集合能够是任何可列举的对象.
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 格式

这个 helper 校验特性的值, 是通过测试他们是否匹配所给予的正则表达式, 详细的声明在 :with 属性.
class Product < ActiveRecord::Base
  validates :legacy_code, format: { with: /\A[a-zA-Z]+\z/,
    message: "only allows letters" }
end

默认的错误信息是 "is invalid".

 

2.6 inclusion 包含

这个 helper 校验的是, 属性的值要被包含在被给予的集合内. 事实上, 这个集合能够是任何可列举的对象.
class Coffee < ActiveRecord::Base
  validates :size, inclusion: { in: %w(small medium large),
    message: "%{value} is not a valid size" }
end

这个 inclusion helper 有一个属性 :in, 接收的一些值的集合是被接受的.

:in 属性有一个别名叫作 :within, 你可以用来表示相同的作用目的, 如果你乐意这样做的话.  前面的例子使用 :message 属性显示你如何能够包含特性的值.
 
对于这个 helper 的默认错误信息是 "is not included in the list".
 

2.7 length 长度

这个 helper 校验的是属性值的长度. 它提供了多种属性, 因此你可以用不同的方式来声明长度的限制:
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 数字化

这个 helper 校验的是, 你的属性必须是数字型的值. 默认的情况下, 它会配对一个可选的标签, 后面跟着的是一个整数型或者浮点数型的数字. 为了详细声明只有整数型的数字才能被允许, 那么需要设置 :only_integer 为 true.
 
如果你设置 :only_integer 为 true, 那么它将会使用
/\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 存在

这个helper校验的是,所声明的属性不能为空。它用 blank? 方法来检查,如果值为 nil 或者空字符串,那就是一个字符串为空或者由空格组成。

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 缺席

这个helper校验的是,所声明的属性是缺席的。它使用 present? 方法来检查,如果这个值不是 nil 或者 一个空的字符串,也就是说,一个字符串是空的或者由空格组成。

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 唯一性

这个 helper 校验的是,该属性值是否唯一,在对象被保存之前。它确实不会在数据库中创建一个唯一性的限制,因此它就可能出现在两个不同的数据库连接里,创建了两条记录是相同的列值,而该列值正是你想要去限制为唯一性的。为了避免这个,你必须这两个列创建一个唯一性索引在你数据库里。参考  the MySQL manual  可以了解到更多关于列的各个索引。

class Account < ActiveRecord::Base
  validates :email, uniqueness: true
end

这校验发生在模型的数据表里执行一个SQL查询时,在那个属性用相同的值查询一个已经存在的记录。

这里有一个 :scope 属性,你能够用来声明其他属性,用来限制唯一性的校验:

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
warning:注意,一些数据库被设置为大小写不明感。
默认的错误消息是 “has already been taken”。
 

2.12 validates_with 校验

 
这个helper 传入的是一个特定的类,用来做校验。

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
 
warning:  增加到 record.errors[:base] 的错误信息与记录的状态相关联, 这被视为一个整体, 而不是一个特殊的特性.
 
validate_with helper 传入一个类, 或则一组类用来执行校验. validates_with 没有默认的错误信息. 在校验的类中, 你必须手工地增加错误信息到记录的错误信息集合中.
 
为了实现校验方法, 你必须拥有一个已经被定义的数据记录行参数, 这个数据记录行会被用来校验.
 
就如同其他的校验, validates_with 有 :if, :unless 和 :on 属性. 如果你带入其他属性, 它会把那些属性发送到校验类中, 作为属性:
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 校验

这个 helper 校验的是属性, 而不是代码块. 没有预定义的校验方法. 你应该使用代码块来创建它, 每一个传入 validates_each 的属性将会被测试. 在下面的例子中, 我们不想 names 和 surnames 开头是小写字母.
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

这个代码块接收到数据记录行, 属性的名称和属性值. 在代码块中你可以做任何你想做的校验. 如果你的校验失败了, 你应该增加一个错误消息到模型中, 因此使它无效.

 

 

0
0
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics