1. Validations Overview
我们经常用到
class Person < ApplicationRecordvalidates :name, presence: true
end
irb> Person.new(name: "John Doe").valid?
=> true
irb> Person.new(name: nil).valid?
=> false
irb> person.errors.objects.first.full_message
=> "Name can't be blank"
可以看到当name没有时Person是无效的。
Validations用于确保只有有效数据才能被保存到数据库中。Rails provides built-in helpers for common needs, and allows you to create your own validation methods as well.意味着可以使用前端验证啥的,但是推荐model-level的验证。
使用new方法实例化一个新对象时,这个对象尚未被保存到数据库中,直到对该对象调用save,它才会被保存到相应的数据库中。Active Record使用persisted?实例方法(或者反义词new_record?)来确定一个对象是否已经存在于数据库中。例如
class Person < ApplicationRecord
end
irb> p = Person.new(name: "Jane Doe")
=> #<Person id: nil, name: "Jane Doe", created_at: nil, updated_at: nil>irb> p.new_record?
=> trueirb> p.persisted?
=> falseirb> p.save
=> trueirb> p.new_record?
=> falseirb> p.persisted?
=> true
保存新纪录将会向数据库发送SQL INSERT 操作,而更新现有记录将发送SQL UPDATE 操作。验证通常会在这些命令发送到数据库之前运行,如果任何验证失败,该对象将被标记为无效并且Active Record 将不会执行 INSERT 或 UPDATE 操作。
2.Validations
Active Record提供了很多预定义验证,可以直接在类定义中使用。这些预定义验证提供了通用的验证规则,每次验证失败时,一个错误的消息会被添加进对象的errors集合中,这个error与正在验证的特殊属性相关联。
当验证失败时,错误信息会存储在errors集合中触发验证的属性名称下。这意味着可以轻松访问与任何特定属性相关的错误。例如,如果validate :name 属性失败,就会在 errors[:name] 下找到错误信息。
当前版本这样写
validates :name, presence: true
旧版本也可以这样写
validates_presence_of :name
另外,所有验证都接受:on 和 :message 选项。:on 选项指定何时触发验证,可能的值是 :create 或 :update。:message 选项允许你定义自定义错误信息,如果验证失败,该信息将被添加到错误集合中。如果不指定信息,Rails 将为该验证使用默认错误信息。
validates :name, presence: true, on: :create
2.1 acceptance
该方法验证提交表单时用户界面上的checkbox 是否被选中。
class Person < ApplicationRecordvalidates :terms_of_service, acceptance: true
end
This check is performed only if terms_of_service
is not nil
. The default error message for this validation is "must be accepted". You can also pass in a custom message via the message
option.
class Person < ApplicationRecordvalidates :terms_of_service, acceptance: { message: "must be agreed to" }
end
它还可以接收一个:accept 选项,该选项决定了接收到的值,默认为 ['1',true],也可以更改:
class Person < ApplicationRecordvalidates :terms_of_service, acceptance: { accept: 'yes' }validates :eula, acceptance: { accept: ['TRUE', 'accepted'] }
end
2.2 format
该验证器通过测试属性值是否匹配给定的正则验证,使用:with选项指定。
class Product < ApplicationRecordvalidates :legacy_code, format: { with: /\A[a-zA-Z]+\z/,message: "only allows letters" }
end
相反,使用 :without 选项可以要求指定属性不匹配正则表达式。
2.3 inclusion
验证属性值是否包含在给定的集合中。
class Coffee < ApplicationRecordvalidates :size, inclusion: { in: %w(small medium large),message: "%{value} is not a valid size" }
end
or
class Coffee < ApplicationRecordvalidates :size, inclusion: { in: ->(coffee) { coffee.available_sizes } }def available_sizes%w(small medium large extra_large)end
end
2.4 length
验证属性值的长度。
class Person < ApplicationRecordvalidates :name, length: { minimum: 2 }validates :bio, length: { maximum: 500 }validates :password, length: { in: 6..20 }validates :registration_number, length: { is: 6 }
end
:minimum | The attribute cannot have less than the specified length. |
:maximum | The attribute cannot have more than the specified length. |
:in | The attribute length must be included in a given interval. The value for this option must be a range. |
:is | The attribute length must be equal to the given value. |
2.5 numericality
验证属性是否只有数值。By default, it will match an optional sign followed by an integer or floating point number.
要指定只允许使用整数,请将 :only_integer 设置为 true,它将使用以下正则表达式验证属性值。
/\A[+-]?\d+\z/
class Player < ApplicationRecordvalidates :points, numericality: truevalidates :games_played, numericality: { only_integer: true }
end
:greater_than | Specifies the value must be greater than the supplied value. | "must be greater than %{count}" |
:greater_than_or_equal_to | Specifies the value must be greater than or equal to the supplied value. | "must be greater than or equal to %{count}" |
:equal_to | Specifies the value must be equal to the supplied value. | "must be equal to %{count}" |
:less_than | Specifies the value must be less than the supplied value. | "must be less than %{count}" |
:less_than_or_equal_to | Specifies the value must be less than or equal to the supplied value. | "must be less than or equal to %{count}" |
:other_than | Specifies the value must be other than the supplied value. | "must be other than %{count}" |
:in | Specifies the value must be in the supplied range. | "must be in %{count}" |
:odd | Specifies the value must be an odd number. | "must be odd" |
:even | Specifies the value must be an even number. | "must be even" |
validates :log_retention_days, numericality: { only_integer: true, greater_than_or_equal_to: 1, less_than_or_equal_to: 14}
2.6 presence
验证属性是否为空。使用Object#blank?方法检测值是否为nil或者空字符串,即空字符串或由空白组成的字符串)。
class Person < ApplicationRecordvalidates :name, :login, :email, presence: true
end
person = Person.new(name: "Alice", login: "alice123", email: "alice@example.com")
person.valid?
=> true # presence validation passesinvalid_person = Person.new(name: "", login: nil, email: "bob@example.com")
invalid_person.valid?
=> false # presence validation fails
2.7 uniqueness
在保存对象之前验证属性值是否唯一。
class Account < ApplicationRecordvalidates :email, uniqueness: true
end
The validation happens by performing an SQL query into the model's table, searching for an existing record with the same value in that attribute.
可以使用 :scope 选项指定一个或多个用于限制唯一性检查的属性:
class Holiday < ApplicationRecordvalidates :name, uniqueness: { scope: :year,message: "should happen once per year" }
end
2.8 validates_each
这个验证针对block,它没有预定义的验证函数,你应该使用block创建一个验证函数,传给validates_each的每个属性都将根据该函数进行测试。
在下面的示例中,我们将拒绝以小写开头的名字和姓氏。
class Person < ApplicationRecordvalidates_each :name, :surname do |record, attr, value|record.errors.add(attr, 'must start with upper case') if /\A[[:lower:]]/.match?(value)end
end
该代码块接收记录、属性名称和属性值。
你可以做任何事情来检查block中的有效数据,如果验证失败,则应在model中添加一个error,从而使其无效。
2.9 validates_with
这个是将记录传递给一个单独的类进行验证。
There is no default error message for validates_with
. You must manually add errors to the record's errors collection in the validator class.
要实现验证方法,必须在方法定义中接受一个record参数,即要验证的记录。
如果想在特定属性上添加错误,可以将其作为第一个参数传递给add方法。
def validate(record)if record.some_field != "acceptable"record.errors.add :some_field, "this field is unacceptable"end
end
validates_with 验证器接收一个类或一个类列表来进行验证。
class Person < ApplicationRecordvalidates_with MyValidator, MyOtherValidator, on: :create
end