Ruby On Rails 笔记4——常用验证上

1. Validations Overview

我们经常用到

ruby 复制代码
class Person < ApplicationRecord
  validates :name, presence: true
end
ruby 复制代码
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?)来确定一个对象是否已经存在于数据库中。例如

ruby 复制代码
class Person < ApplicationRecord
end
ruby 复制代码
irb> p = Person.new(name: "Jane Doe")
=> #<Person id: nil, name: "Jane Doe", created_at: nil, updated_at: nil>

irb> p.new_record?
=> true

irb> p.persisted?
=> false

irb> p.save
=> true

irb> p.new_record?
=> false

irb> p.persisted?
=> true

保存新纪录将会向数据库发送SQL INSERT 操作,而更新现有记录将发送SQL UPDATE 操作。验证通常会在这些命令发送到数据库之前运行,如果任何验证失败,该对象将被标记为无效并且Active Record 将不会执行 INSERT 或 UPDATE 操作。

2.Validations

Active Record提供了很多预定义验证,可以直接在类定义中使用。这些预定义验证提供了通用的验证规则,每次验证失败时,一个错误的消息会被添加进对象的errors集合中,这个error与正在验证的特殊属性相关联。

当验证失败时,错误信息会存储在errors集合中触发验证的属性名称下。这意味着可以轻松访问与任何特定属性相关的错误。例如,如果validate :name 属性失败,就会在 errors[:name] 下找到错误信息。

当前版本这样写

ruby 复制代码
validates :name, presence: true

旧版本也可以这样写

ruby 复制代码
validates_presence_of :name

另外,所有验证都接受:on 和 :message 选项。:on 选项指定何时触发验证,可能的值是 :create 或 :update。:message 选项允许你定义自定义错误信息,如果验证失败,该信息将被添加到错误集合中。如果不指定信息,Rails 将为该验证使用默认错误信息。

ruby 复制代码
 validates :name, presence: true, on: :create

2.1 acceptance

该方法验证提交表单时用户界面上的checkbox 是否被选中。

ruby 复制代码
class Person < ApplicationRecord
  validates :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.

ruby 复制代码
class Person < ApplicationRecord
  validates :terms_of_service, acceptance: { message: "must be agreed to" }
end

它还可以接收一个:accept 选项,该选项决定了接收到的值,默认为 ['1',true],也可以更改:

ruby 复制代码
class Person < ApplicationRecord
  validates :terms_of_service, acceptance: { accept: 'yes' }
  validates :eula, acceptance: { accept: ['TRUE', 'accepted'] }
end

2.2 format

该验证器通过测试属性值是否匹配给定的正则验证,使用:with选项指定。

ruby 复制代码
class Product < ApplicationRecord
  validates :legacy_code, format: { with: /\A[a-zA-Z]+\z/,
    message: "only allows letters" }
end

相反,使用 :without 选项可以要求指定属性不匹配正则表达式。

2.3 inclusion

验证属性值是否包含在给定的集合中。

ruby 复制代码
class Coffee < ApplicationRecord
  validates :size, inclusion: { in: %w(small medium large),
    message: "%{value} is not a valid size" }
end

or

ruby 复制代码
class Coffee < ApplicationRecord
  validates :size, inclusion: { in: ->(coffee) { coffee.available_sizes } }

  def available_sizes
    %w(small medium large extra_large)
  end
end

2.4 length

验证属性值的长度。

ruby 复制代码
class Person < ApplicationRecord
  validates :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,它将使用以下正则表达式验证属性值。

ruby 复制代码
/\A[+-]?\d+\z/
ruby 复制代码
class Player < ApplicationRecord
  validates :points, numericality: true
  validates :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" |

ruby 复制代码
  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或者空字符串,即空字符串或由空白组成的字符串)。

ruby 复制代码
class Person < ApplicationRecord
  validates :name, :login, :email, presence: true
end
ruby 复制代码
person = Person.new(name: "Alice", login: "alice123", email: "alice@example.com")
person.valid?
=> true # presence validation passes

invalid_person = Person.new(name: "", login: nil, email: "bob@example.com")
invalid_person.valid?
=> false # presence validation fails

2.7 uniqueness

在保存对象之前验证属性值是否唯一。

ruby 复制代码
class Account < ApplicationRecord
  validates :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 选项指定一个或多个用于限制唯一性检查的属性:

ruby 复制代码
class Holiday < ApplicationRecord
  validates :name, uniqueness: { scope: :year,
    message: "should happen once per year" }
end

2.8 validates_each

这个验证针对block,它没有预定义的验证函数,你应该使用block创建一个验证函数,传给validates_each的每个属性都将根据该函数进行测试。

在下面的示例中,我们将拒绝以小写开头的名字和姓氏。

ruby 复制代码
class Person < ApplicationRecord
  validates_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方法。

ruby 复制代码
def validate(record)
  if record.some_field != "acceptable"
    record.errors.add :some_field, "this field is unacceptable"
  end
end

validates_with 验证器接收一个类或一个类列表来进行验证。

ruby 复制代码
class Person < ApplicationRecord
  validates_with MyValidator, MyOtherValidator, on: :create
end
相关推荐
fredricen1 个月前
使用VSCode搭建Ruby on Rails集成开发环境
ide·vscode·ruby on rails
haiyu柠檬2 个月前
Ruby On Rails 笔记5——常用验证下
ruby on rails
haiyu柠檬3 个月前
Ruby On Rails 笔记2——表的基本知识
数据库·笔记·ruby on rails
haiyu柠檬3 个月前
Ruby On Rails 笔记1——Rails 入门
笔记·ruby on rails
微信-since811923 个月前
【ruby on rails】dup、deep_dup、clone的区别
数据结构·后端·ruby on rails
微信-since811923 个月前
[ruby on rails] 安装docker
后端·docker·ruby on rails
江河湖海3 个月前
3. 用Ruby on Rails创建一个在线商城
后端·ruby on rails
yagas7 个月前
使用puma部署ruby on rails的记录
后端·ruby on rails
小筱在线7 个月前
如何在Linux上部署Ruby on Rails应用程序
linux·运维·ruby on rails