数据验证概览

为什么要做数据验证

数据验证确保只有有效的数据才能存入数据库,在模型中做验证是最有保障的,只有通过验证的数据才能存入数据库。数据验证和使用的数据库种类无关,终端用户也无法跳过,而且容易测试和维护。

数据验证的方式主要有数据库原生约束、客户端验证和控制器层验证:

  • 数据库约束无法兼容多种数据库,难以测试和维护,但是如果其他应用也要使用这个数据库,最好能够在数据库层做一些约束。

  • 客户端验证可靠性不高,但是和其他验证方式结合可以提供实时反馈

  • 控制器层验证不灵便,难以测试和维护,只要可能就应该保证控制器的代码简洁,这样才有利于长远发展

Active Record 对象分为两种,一种在数据库中有对应记录,一种没有,新建对象还不属于数据库,只有调用了 save 方法后,才会存入数据库,可以使用 new_record? 方法判断是否存入数据库,未存入则返回 true ,存入则返回 false

新建并保存会执行 SQL INSERT 操作,更新记录会执行 SQL UPDATE 操作,一般情况下,数据验证发生在执行这些SQL语句之前,如果验证失败,对象会被标记为无效, Active Record 不会向数据库发送指令。

以下方法会触发数据验证:

  • create

  • create!

  • save

  • save!

  • update

  • update!

炸弹方法会在验证失败后抛出异常。

以下方法会跳过验证,不管验证是否通过都会把对象存入数据库:

  • decrement!

  • decrement_counter

  • increment!

  • increment_counter

  • toggle!

  • touch

  • update_all

  • update_attribute

  • update_column

  • update_columns

  • update_counters

同时,使用 save 方法时,如果传入 validate: false 参数,也会跳过验证。

同时,也可以使用 valid? 方法自己执行验证,如果对象上没有错误则返回 true ,否则返回 falseinvalid? 方法则相反。执行验证之后,错误可以通过实例方法 errors.message 获取,这个方法返回一个错误集合,如果为空,则说明对象是有效的。需要注意的是,如果没有验证数据,这个方法返回的也是一个空集合。

如果要验证某个属性是否有效,可以使用 errors[:attribute] ,这返回一个包含了所有错误的数组,如果没有错误则返回空数组,这个方法和 invalid? 方法不一样,这个方法不会验证整个对象,只会检查某个属性是否有错。

可以使用 errors.details[:attribute] 检查到底是哪个验证导致属性无效,这个方法返回一个由散列组成的数组。

数据验证的辅助方法

辅助方法可以直接在模型中使用,这些方法提供了常用的验证规则,验证失败就会向对象的 errors 集合中添加一个消息。

每个辅助方法都可以接受任意个属性名,所以一行代码可以在多个属性上做同一种验证。

acceptance

检查表单提交时,用户界面中的复选框是否被选中,一般用来要求用户接受应用的服务条款、确保用户阅读了一些文本等。

class Person < ApplicationRecordvalidates :terms_of_service, acceptance: true
end
复制代码

validates_associated

如果模型与其他模型有关联,而且关联的模型也需要验证,就是用这个方法,保存对象时,会在相关联的每个对象上调用 valid? 方法。

class Library < ApplicationRecord has_many :booksvalidates_associated :books
end
复制代码

不要在关联的两端使用,这样会造成无限的循环

confirmation

检查两个文本字段的值是否完全相同,如确认邮件地址或者密码。这个验证创建一个虚拟属性,其名字为要验证的属性名后加 _confirmation

class Person < ApplicationRecordvalidates :email, confirmation: true
end
复制代码

在视图模板中视图可以如下:

<%= text_field :person, :email %>
<%= text_field :person, :email_confirmation %>
复制代码

因为只有在 email_confirmation 值不是 nil 时才会验证,所以需要添加存在性验证

class Person < ApplicationRecordvalidates :email, confirmation: truevalidates :email_confirmation, presence: true
end
复制代码

使用 :case_sensitive 选项可以说明是否区分大小写,这个选项默认值是true

class Person < ApplicationRecordvalidates :email, confirmation: {case_sensitive: false}
end
复制代码

exclusion

这个方法检查属性的值是否不在指定的集合中,集合可以是任何一种可枚举的对象

class Account < Applicationvalidates :subdomain, exclusion: {in: %w(www us ca jp), message: "%{value} is reserved"}
end
复制代码

in 选项设置哪些值不能作为属性的值,in 的别名是 with

formate

这个方法检查属性的值是否匹配 :with 选项指定的正则表达式。

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

inclusion

这个方法检查属性的值是否在指定的集合中,集合可以是任何一种可枚举的对象

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

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:最短长度

  • :maximum:最长长度

  • :in 或者 :within:长度范围

  • :is:等于该长度

定制错误消息可以使用 :wrong_length:too_long:too_short 选项,%{count} 表示长度限制的值

class Person < ApplicationRecordvalidates :bio, length: {maximum: 1000, too_long: "%{count} characters is the maximum allowed"}
end
复制代码

numericality

检查属性是否只包含数字,默认匹配的值是可选的正负符号后加整数或浮点数,如果只接受整数,把 :only_integer 选项设置为 true,否则会使用Float把值转换为数字。

class Player < ApplicationRecordvalidates :points, numericality: truevalidates :games_played< numericality: {only_integer: true}
end
复制代码

除此之外,这个方法还可指定以下选项:

  • :greater_than :属性值需大于 >

  • :greater_than_or_equal_to :>=

  • :equal_to :=

  • :less_than :<

  • :less_than_or_equal_to :<=

  • :other_than :!=

  • :odd :必须为奇数

  • :even :必须为偶数

此方法默认不接受 nil 值,可以使用 allow_nil: true 选项允许接受 nil

presence

检查属性是否为非空值,方法调用 blank? 方法检查是否为 nil 或空字符串

class Person < ApplicationRecordvalidates :name, :login, :email, presence: true
end
复制代码

absence

验证属性值是否为空,使用 present? 方法检查是否为 nil 或空字符串

class Person < ApplicationRecordvalidates :name, :login, :email, absence: true
end
复制代码

uniqueness

这个方法在保存对象前验证属性值是否唯一,这个方法不会在数据库中创建唯一性约束,所以有可能两次数据库连接创建的记录具有相同的值,所以最好在数据库字段上建立唯一性约束。

class Account < ApplicationRecordvalidates :email, uniqueness: true
end
复制代码

这个验证会在模型对应的表中执行一个 SQL 查询,检查现有的记录中该字段是否已经出现过相同的值。

可以使用 :case_sensitive 选项

class Person < ApplicationRecordvalidates :name, uniqueness: {case_sensitive: false}
end
复制代码

validates_with

这个方法把记录交给其他类做验证。

class GoodnessValidator < ActiveModel::Validatordef validate(record)if record.first_name == "Evil"record.errors[:base] << "This person is evil"endend
endclass Person < ApplicationRecordvalidates_with GoodnessValidator
end
复制代码

这个方法的参数是一个类或者一组类。

validates_each

这个方法使用代码块中的代码验证属性,需要在代码块中定义验证方式。

class Person < ApplicationRecordvalidates_each :name, :surname do |record, attr, value|record.errors.add(attr, 'must start with upper case') if value =~/\A[[:lower:]]/end
end
复制代码

代码块的参数是记录、属性名和属性值。

常用验证选项

:allow_nil

允许 nil 值,如果要验证的值是 nil 就跳过验证

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

:allow_blank

与上面方法类似,使用 blank? 方法判断,空字符串和nil时跳过验证

:message

添加错误消息,消息中可以包含 %{value}%{attribute}%{model}

:on

指定验证时机,默认都在保存时验证,使用使用

  • on: :create :只在创建时验证

  • on: :update:只在更新时验证

class Person < ApplicationRecord# 更新时允许电子邮件地址重复validates :email, uniqueness: true, on: :create# 创建记录时允许年龄不是数字validates :age, numericality: true, on: :update# 默认行为(创建和更新时都验证)validates :name, presence: true
end
复制代码

:strict

使用严格验证模式,对象无效时抛出异常


class Person < ApplicationRecordvalidates :name, presence: { strict: true }
endPerson.new.valid?  # => ActiveModel::StrictValidationFailed: Name can't be blank复制代码

条件验证

使用 :if:unless 选项只有满足特定条件才验证,值可以是符号、字符串、Proc或数组。 选项为符号时,表示验证之前执行对应的方法。这是最常用的设置方法。

class Order < ApplicationRecordvalidates :card_number
end
复制代码

自定义验证

自定义验证类继承自 ActiveModel::Validator,必须实现validate方法,参数是要验证的记录


class MyValidator < ActiveModel::Validatordef validate(record)unless record.name.starts_with? 'X'record.errors[:name] << 'Need a name starting with X please!'endend
endclass Personinclude ActiveModel::Validationsvalidates_with MyValidator
end
复制代码

验证错误处理

ActiveModel::Errors 的实例包含所有的错误,键是每个属性的名称,只是一个数组,包含错误消息字符串。

errors[] 用于获取某个属性上的错误消息

errors.add 用于手动添加某属性的错误消息,参数是属性和错误消息

errors.details 返回错误详情

errors.clear 清楚errors集合中的所有消息

errors.size 返回错误消息总数。

Active Record 数据验证相关推荐

  1. Active Record Query Interface 数据查询接口(界面) 看到第8节。

    http://guides.rubyonrails.org/active_record_querying.html ✅How to find records using a variety of me ...

  2. Active Record

    class Data extends CI_Controller {function index(){echo 'Hwllo DBer';}//多结果标准查询(对象形式)function select ...

  3. java ldap操作实例_Java Spring Security示例教程中的2种设置LDAP Active Directory身份验证的方法...

    java ldap操作实例 LDAP身份验证是世界上最流行的企业应用程序身份验证机制之一,而Active Directory (Microsoft为Windows提供的LDAP实现)是另一种广泛使用的 ...

  4. Java Spring Security示例教程中的2种设置LDAP Active Directory身份验证的方法

    LDAP身份验证是全球范围内最流行的企业应用程序身份验证机制之一,而Active Directory (Microsoft针对Windows的LDAP实现)是另一种广泛使用的LDAP服务器. 在许多项 ...

  5. php activerecord,Yii2 优雅的 Active Record

    这篇文章我们来看看在 Yii2 之中的 Active Record,为啥要将 Active Record 单独出来说呢?因为个人认为这是 Yii(不管是 Yii1.1 还是 Yii2)最强大的一部分功 ...

  6. Android开源库--ActiveAndroid(active record模式的ORM数据库框架)

    Github地址:https://github.com/pardom/ActiveAndroid 前言 我一般在Android开发中,几乎用不到SQLlite,因为一些小数据就直接使用Preferen ...

  7. DAL、DAO、ORM、Active Record讲解

    目录 模型(Model) 持久层(Persistence) DAL(Data Access Layer,数据访问层) DAO(Data Access Object,数据访问对象) ORM(Object ...

  8. excel 中vb组合框_Excel表中的数据验证组合框

    excel 中vb组合框 There are instructions on my Contextures website for using a combo box with data valida ...

  9. Spring Boot 框架学习笔记(二)(配置文件与数据注入 yaml基本语法 JSR303数据验证 多环境切换 )

    Spring Boot 框架学习笔记(二) 六.appliaction.properties配置与数据注入 6.1 `@Value`注解 测试注入数据 读取输入流 6.2 读取配置文件数据注入 单文件 ...

最新文章

  1. python画图程序-编程入门06:Python海龟绘图
  2. Go Iris 中间件
  3. python对象没有属性_Python-对象没有属性E
  4. Spring MVC集成slf4j-logback
  5. LeetCode 1825. 求出 MK 平均值(set + queue)
  6. 实现自适应位置--footer紧贴浏览器底部
  7. Spring中的InitializingBean接口
  8. sql取最大值的那一行_SQL高级功能
  9. aboutsqlserver.com:mvp
  10. Gigapixel AI 6.0 for Mac(图片无损放大软件)
  11. Stencil Buffer(模板缓冲区)
  12. 啦啦外卖独立版七牛云配置失败解决方案
  13. ToStringBuilder.reflectionToString用法
  14. html简单网页源代码表格,HTML 表格
  15. window.crypto.subtle进行rsa-oaep加密
  16. Java生成bmp图片_利用24位BMP图实现信息隐写(java语言)
  17. python爬取淘宝数据魔方_看我是怎么使用淘宝数据魔方--巧用数据魔方把握市场信息...
  18. 笑声的音效素材,几百个你想要的都在这
  19. 你越来越孤独的3个原因
  20. 图解FDISK与FORMAT命令分区与格式化

热门文章

  1. linux下source命令使用详解
  2. C++ vector的初始化、添加、遍历、插入、删除、查找、排序、释放操作
  3. CentOS 7.6 安装 Mysql8.0.17 rpm-bundle.tar解包 rpm安装(个人未验证)
  4. c++一个问题:while(!cin) 的解释
  5. 5-简单选择排序C实现(递增递减的简单转换)
  6. 矩阵A对任意的可逆矩阵p都有Ap=pA,证明A为数量矩阵
  7. java 调 cmd 没反应
  8. eclipse如何部署到tomcat上的
  9. Identityserver4中ResourceOwnerPassword 模式获取refreshtoken
  10. Poj - 3254 Corn Fields (状压DP)(入门)