[Rails] Active Record Validations(Model 資料驗證)
keywords: 資料驗證
, valid
, error
資料驗證這件事在 Rails 的 MVC 三分天下的架構中,Controller 跟 Model 都可以做這件事,要在 View 裡寫 JavaScript 做檢查也可以,但這件事如果交給 Controller 或 View 來做的話,一來會讓程式碼的邏輯變得更複雜,二來這個驗證也不容易被重複使用,也不容易被測試,所以資料機制寫在 Model 裡是比較合理而且單純的。
Active Record Validations @ RailsGuides
Model 資料驗證設定
除了 presence 之外,Rails 還有提供其它像是 uniqueness、length 或 numericality 等便利的驗證器,使用方法可直接參考 Rails Guide 的 Active Record Validations 章節。
範例一
#####################################################
## 在 Model 中進行資料驗證 ##
#####################################################
class Candidate < ApplicationRecord
validates :name, presence: true # 寫法一
validates_presence_of :party # 寫法二
end
範例二
validates
:是標 準 Rails 的驗證器(validator)
presence: true
:則是告訴驗證器要驗證每個欄位是否存在,而且不是空值。
numericality
: 用來確認內容是有效的數值
uniqueness
:檢驗資料庫中有無具有相同 title 的列
allow_blank
:用來允許欄位是空值
class Product < ApplicationRecord
validates :title, :description, :image_url, presence: true
validates :price, numericality: {greater_than_or_equal_to: 0.01}
validates :title, uniqueness: true
validates :image_url, allow_blank: true, format:{
with: %r{\.(gif|jpg|png)\Z}i,
message: 'must be a URL for GIF, JPG or PNG image.'
}
end
檢視錯誤訊息
# 在 Rails Console 中測試
c1 = Candidate.new
c1.errors.any? # 回傳 false,檢驗 c1 有無錯誤
c1.valid? # 驗證資料格式是否正確(透過 save 也會進行驗證)
c1.errors.any? # 回傳 true
c1.errors.full_messages # 回傳 "Name can't be blank",顯示錯誤訊息內容
c1.save(validates: false) # 跳過資料驗證
注意事項
雖然驗證功能很方便,但並不是每種方法都會觸發驗證,僅有以下這些方法會觸發驗證 create
, create!
, save
, save!
, update
, update!
,而 toggle!
或 increment!
等方法會跳過驗證流程。
有驚嘆號版本的,如果驗證未通過會產生錯誤訊息,而沒有驚嘆號版本則僅會回傳該 Model 的一個空物件。
客制化資料驗證
方法一:遵循 Rails 驗證器規則
這個驗證器可以跟其它內建的驗證器一起混著使用,使用起來會更簡潔。要寫這樣的驗證器需要符合 Rails Validator 的命名規則:
- 參數是 begin_with_ruby 的話,類別名稱則是 BeginWithRuby 加上 Validator,並繼承自 ActiveModel::EachValidator 類別。
- 必須實作 validate_each 方法。
# 客制化驗證器(class)要放在驗證步驟(validates)前
class BeginWithRubyValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
unless value.starts_with? 'Ruby'
record.errors[attribute] << "必需是 Ruby 開頭喔!"
end
end
end
validates :name, begin_with_ruby: true
方法二:使用 validate 自己寫判斷
class Candidate < ApplicationRecord
validate :name_validator # 這裡是 validate(單數)不是上面的 validates
private
def name_validator
unless name.starts_with? 'Ruby'
errors[:name] << '必需是 Ruby 開頭喔!' # 當不符合規定時,就在 errors 的 Hash 裡面塞錯誤訊息。
end
end
end
關閉錯誤區塊(field with errors)
keywords: field_with_errors
當表單驗證出現錯誤時,會自動為該 input 帶上一個 .field_with_errors
的 <div>
區塊。如果不希望出現此區塊,可以在 config/environment.rb
中加上:
# ./OnePageShop/config/environment.rb
ActionView::Base.field_error_proc = Proc.new do |html_tag, instance|
html_tag.html_safe
end
範例
# ./OnePageShop/app/models/invoice.rb
class Invoice < ApplicationRecord
validates :address_line, presence: true
validates :ban, :company, presence: true, if: :is_three_copies?
private
def is_three_copies?
inv_type == 'three_copies'
end
end
參考
- Active Record Validations @ RailsGuides
- Model 驗證及回呼 @ 為你自己學 Ruby on Rails