在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ Ruby/ 4.4 模型中的校驗(yàn)(Validates)
寫在后面
寫在前面
第六章 Rails 的配置及部署
第四章 Rails 中的模型
4.4 模型中的校驗(yàn)(Validates)
1.3 用戶界面(UI)設(shè)計(jì)
6.5 生產(chǎn)環(huán)境部署
3.2 表單
4.3 模型中的關(guān)聯(lián)關(guān)系(Relations)
4.5 模型中的回調(diào)(Callback)
第五章 Rails 中的控制器
4.2 深入模型查詢
5.2 控制器中的方法
6.2 緩存
3.4 模板引擎的使用
6.4 I18n
第一章 Ruby on Rails 概述
6.6 常用 Gem
1.2 Rails 文件簡介
2.2 REST 架構(gòu)
2.3 深入路由(routes)
第三章 Rails 中的視圖
6.3 異步任務(wù)及郵件發(fā)送
第二章 Rails 中的資源
3.3 視圖中的 AJAX 交互

4.4 模型中的校驗(yàn)(Validates)

概要:

本課時(shí)講解 Model 中的屬性校驗(yàn)方法,以及在頁面上顯示校驗(yàn)失敗信息。

知識(shí)點(diǎn):

  1. validates 方法
  2. errors
  3. helpers
  4. I18n
  5. Rspec

正文

4.4.1 數(shù)據(jù)校驗(yàn)

我們將數(shù)據(jù)保存到數(shù)據(jù)庫的時(shí)候,可以有兩種數(shù)據(jù)校驗(yàn),一種是在數(shù)據(jù)庫中設(shè)定驗(yàn)證規(guī)則,一種是在程序中進(jìn)行校驗(yàn)。

Rails 為我們提供了方便的屬性校驗(yàn)。在 [4.2.1 兩個(gè) Gem] 一節(jié),我們介紹了ActiveRecord 中包含的兩個(gè) Gem,在數(shù)據(jù)查詢和關(guān)聯(lián)關(guān)系中,我們主要使用的是 arel。數(shù)據(jù)校驗(yàn)時(shí),我們使用的是 ActiveModel

4.4.2 校驗(yàn)方法

4.4.2.1 常用的校驗(yàn)方法

方法 含義 例子
acceptance 必須接受選項(xiàng),比如注冊條款(必須同意) validates :terms_of_service, acceptance: true
validates_associated 校驗(yàn)關(guān)聯(lián)資源,僅在關(guān)聯(lián)的一端使用即可,避免循環(huán)校驗(yàn) [1]
confirmation 填寫確認(rèn) validates :email, confirmation: true
exclusion 排除內(nèi)容,如某些保留關(guān)鍵詞不允許注冊使用 validates :subdomain, exclusion: { in: %w(www us ca jp), message: "%{value} is reserved." }
format 格式化,如郵件格式 validates :legacy_code, format: { with: /\A[a-zA-Z]+\z/, message: "only allows letters" }
inclusion 包含內(nèi)容,如特定的輸入內(nèi)容 validates :size, inclusion: { in: %w(small medium large), message: "%{value} is not a valid size" }
length 內(nèi)容長度 validates :name, length: { minimum: 2 } [2]
numericality 僅數(shù)字 validates :points, numericality: true
presence 必填,使用 blank? 方法判斷 validates :name, :login, :email, presence: true [3] [4]
absence 必空,使用 present? 判斷 [5]
uniqueness 唯一 validates :email, uniqueness: true [6]

注解:

[1]

class Library < ActiveRecord::Base
  has_many :books
  validates_associated :books
end
[2] 有其他幾個(gè)選項(xiàng):

minimum,最短長度

maximum,最大長度
in/:within,在某范圍
is,指定長度

[3] 也可以應(yīng)用在關(guān)聯(lián)關(guān)系上,如:

class LineItem < ActiveRecord::Base
  belongs_to :order
  validates :order, presence: true
end

為了保持內(nèi)存中引用相同地址,需要在 Order 上使用 inverse_of:

class Order < ActiveRecord::Base
  has_many :line_items, inverse_of: :order
end

[4] 進(jìn)入 console,做個(gè)試驗(yàn):

false.blank?
  => true 
true.blank?
  => false

所以,使用 presence 判斷 true/false 屬性時(shí),需要這樣使用:

validates :boolean_field_name, presence: true
validates :boolean_field_name, inclusion: { in: [true, false] }
validates :boolean_field_name, exclusion: { in: [nil] }

[5] 和 presence 一樣,需要使用 inverse_of 限定關(guān)聯(lián)關(guān)系,并且在判斷 true/false 時(shí):

validates :boolean_field_name, absence: true
validates :boolean_field_name, exclusion: { in: [true, false] }

[6] uniqueness 有兩個(gè)重要的選項(xiàng)。

scope,比如:

validates :number, uniqueness: { scope: : company_id }

保存到數(shù)據(jù)庫前,uniqueness 會(huì)先檢索數(shù)據(jù)庫是否已經(jīng)存在該字段的值,scope 可以使檢索時(shí)附帶一個(gè)字段,比如:不同的公司,可以有相同的訂單號,而同公司訂單號必須唯一。

validates :name, uniqueness: { case_sensitive: false }

默認(rèn)是 true,區(qū)分大小寫。改為 false,可不區(qū)分大小寫。

4.4.2.2 校驗(yàn)方法中的選項(xiàng)

在檢驗(yàn)方法 validates 中,可以使用幾個(gè)選項(xiàng):

選項(xiàng) 含義 例子
allow_nil 是否允許為 nil validates :size, allow_nil: true
allow_blank 是否允許為 blank?,為 false 時(shí),不可填寫 "", false, nil validates :title, allow_blank: true
message 自定義錯(cuò)誤信息 validates :subdomain, exclusion: { in: %w(www us ca jp), message: "%{value} 為保留關(guān)鍵詞" }
on 選擇在 create 或 update 上使用校驗(yàn) validates :email, uniqueness: true, on: :create
strict 校驗(yàn)失敗時(shí)拋出異常,或自定異常類 validates :name, presence: { strict: true } [1]

注解

[1]

自定義異常類

class Person < ActiveRecord::Base
  validates :token, presence: true, uniqueness: true, strict: TokenGenerationException
end

Person.new.valid? 
=> TokenGenerationException: Token can't be blank

4.4.3 觸發(fā)校驗(yàn)方法

在將數(shù)據(jù)保存到數(shù)據(jù)庫的時(shí)候,有些方法,會(huì)觸發(fā)校驗(yàn),有些則直接發(fā)送數(shù)據(jù)庫 sql 命令,不觸發(fā)校驗(yàn)。

4.4.3.1 觸發(fā)校驗(yàn)的方法

  • create
  • create!
  • save
  • save!
  • update
  • update!

! 結(jié)尾的方法,在校驗(yàn)失敗時(shí),會(huì)拋出異常。save(validate: false) 可以跳過 save 方法的校驗(yàn)。

4.4.3.2 不觸發(fā)校驗(yàn)的方法

  • decrement!
  • decrement_counter
  • increment!
  • increment_counter
  • toggle!
  • touch
  • update_all
  • update_attribute
  • update_column
  • update_columns
  • update_counters

4.4.3.2 有條件的校驗(yàn)

我們可以在校驗(yàn)中增加 :if:unless 條件判斷。

class Order < ActiveRecord::Base
  validates :card_number, presence: true, if: :paid_with_card?
  def paid_with_card?
    payment_type == "card"
  end
end

這里使用的是方法判斷,也可以直接使用字符串,比如:

class Person < ActiveRecord::Base
??validates :surname, presence: true, if: "name.nil?"
end

或者一個(gè)代碼塊:

class Account < ActiveRecord::Base
  validates :password, confirmation: true, unless: Proc.new { |a| a.password.blank? }
end

4.4.3.3 valid? 方法

valid?invalid? 方法會(huì)觸發(fā)校驗(yàn)。校驗(yàn)成功時(shí)返回 true,失敗時(shí),返回 false,并且將校驗(yàn)信息放入 errors 類。訪問 order.errors,返回的是 ActiveModel::Errors 實(shí)例,它的代碼在 這里。

4.4.4 Errors 對象

校驗(yàn)失敗時(shí),model.errors 會(huì)保存入校驗(yàn)的屬性和失敗原因。我們可以通過幾個(gè)方法,從 errors 實(shí)例中拿到具體的信息。

% model.errors.messages
=> {:number=>["must be blank"]} 

messages 方法返回的是 hash 結(jié)構(gòu)的信息,key 是校驗(yàn)的屬性。

% model.errors.full_messages
=> ["Number can't be blank", ...]

full_messages 方法返回 Array 結(jié)構(gòu)的完整錯(cuò)誤信息。這在資源編輯的 form 頁面,可以整體輸出錯(cuò)誤信息,不過它沒有具體到某個(gè)屬性上。對于某個(gè)屬性,我們可以使用 errors[:number] 來讀取:

% order.errors[:number]
=> ["can't be blank"] 

在某些時(shí)候,我們需要添加自己的信息,可以使用:

order.errors.add(:number, "訂單號不能含有 !@#%*()_-+= 等字符")

如果添加的信息,并不一定是某個(gè)具體屬性,可以添加到errors 的 base 中:

order.errors.add(:base, "訂單格式不正確")

order.errors.clear,可以清理掉所有信息.

4.4.5 使用中文的校驗(yàn)信息

我們已經(jīng)注意到了,目前所有的校驗(yàn)信息都是英文的,雖然可以在自定義信息里寫入中文(Not Rails Style),但是我們可以利用 Rails 提供的 I18n gem,實(shí)現(xiàn)文本內(nèi)容的漢化。這包括異常信息。

我們先修改一下 I18n 文件加載地址,在 application.rb 文件里,我們找到這一段:

config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**/*.{rb,yml}').to_s]
config.i18n.default_locale = :"zh-CN"

這樣會(huì)加載我們在 config/locales 中的全部語言包文件(注意,這里使用的是 **/*.{rb,yml})。

我們創(chuàng)建語言包,為了便于維護(hù),我在這里做了細(xì)分,大家可以在 這里 查看。

進(jìn)到終端里,測試下:

% product = Product.new
% product.valid?
=> false
% product.errors.full_messages
=> ["名稱不能為空字符"] 

在后面的章節(jié)里,會(huì)專門講解 I18n 的問題,如果不像本例子中自己添加語言包,也可以安裝 rails-i18n 這個(gè) gem 來解決問題。

4.4.5.1 頁面中顯示錯(cuò)誤信息

為了讓頁面集中的顯示錯(cuò)誤信息,我們在 form 中使用了局部模板,把校驗(yàn)失敗的內(nèi)容顯示在輸入框的頂部。

<% if @product.errors.any? %>
  <div id="error_expl" class="panel panel-danger">
    <div class="panel-heading">
      <h3 class="panel-title"><%= pluralize(@product.errors.count, "error") %> prohibited this product from being saved:</h3>
    </div>
    <div class="panel-body">
      <ul>
      <% @product.errors.full_messages.each do |msg| %>
        <li><%= msg %></li>
      <% end %>
      </ul>
    </div>
  </div>
<% end %>

full_messages 返回 Array 的校驗(yàn)信息,我們只需循環(huán)顯示即可。如果想在輸入框旁邊顯示信息,可以單獨(dú)讀取該屬性,比如 @product.errors[:name],可以放到一個(gè) jquery 的 tooltip 中。

不過,這種信息是要提交到服務(wù)器端處理后,才能顯示出來的。為了在頁面端就顯示校驗(yàn),我們還是需要 jQuery 插件的。

4.4.5.2 jQuery 校驗(yàn)

Form 校驗(yàn)的時(shí)候,有兩個(gè)插件較常用。

http://jqueryvalidation.org/ 是較常用的一個(gè),也很簡單,但是需要在頁面上顯示中文,還需要它的中文插件。

<%= javascript_include_tag 'spree/jquery.validate/localization/messages_zh' %>

中文語言包的源碼在[這里] (https://github.com/jzaefferer/jquery-validation/blob/master/src/localization/messages_zh.js)。

如果不需要校驗(yàn)具體信息,因?yàn)槲覀円呀?jīng)使用了 bootstrap 這個(gè)前端框架,所以我們可以使用它的表單校驗(yàn):http://bootstrapvalidator.com

它會(huì)按照 bootstrap 的方式,將輸入框加上圖標(biāo),使校驗(yàn)更加直觀。當(dāng)然,你還可以讀取具體的屬性信息,放到 bootstrap 的 tooltip 里。

4.4.6 Rspec

和上一張的關(guān)聯(lián)關(guān)系一樣,shoulda-matchers 也提供了方便的校驗(yàn)測試框架。

describe Product do
  it { should validate_presence_of(:name) }
end

現(xiàn)在我們給 Model 增加了越來越多的內(nèi)容,為了方便找到方法,我們可以對代碼進(jìn)行一個(gè)簡單的分割,這樣就不會(huì)在測試和對應(yīng)的業(yè)務(wù)代碼間切換浪費(fèi)時(shí)間了。

# extends ...................................................................
# includes ..................................................................
# security ..................................................................
# relationships .............................................................
# validations ...............................................................
# callbacks .................................................................
# scopes ....................................................................
# additional config .........................................................
# class methods .............................................................
# public instance methods ...................................................
# protected instance methods ................................................
# private instance methods ..................................................