除了Rails本身提供的基本驗證之外,有時候我們會需要客製化驗證,這時候我們可以在 Modle中定義方法來使用,使用方式如下:
自訂驗證方法
class User < ApplicationRecord
validate :name_validator
private
def name_validator
unless name.starts_with? 'Ruby'
errors[:name] << 'must begin with Ruby'
end
end
end
只要errors的hash有東西,存檔(驗證)就不會成功。
在你的驗證方法之中,你會使用到 errors 來將錯誤訊息放進去,如果這個錯誤是因為某一屬性造成,我們就用那個屬性當做 errors 的 key,例如本例的 :name。如果原因不特別屬於某一個屬性,照慣例會用 :base。
但是當你有很多個Model都需要做同樣的驗證時,直接定義在某個Model之下就不會是個很好的做法;
這時,你可以使用下面的Custom Validators,另外建立一個驗證類別,讓多個Model可以使用。
Custom Validators 自訂資料驗證器
只要符合ActiveModel::Validations::ClassMethods 驗證的規定,你可以另外自訂一個驗證類別,並且使用include和validates_with把它呼叫進要驗證的Model,或是直接用validate_each來實現:
簡單的規範如下:
驗證類別必需繼承自ActiveModel::Validator,
類別名稱要是自定義名稱Validator
類別內必須要有一個validate或是validate_each的function並且接受對應參數
使用validate_each:
當遇到email:trueRails會尋找EmailValidator的類別並且使用 validate_each 方法來做驗證。
class EmailValidator < ActiveModel::EachValidator
def validate_each(record, attr_name, value)
unless value =~ /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i
record.errors.add :email, "This is some complex validation"
end
end
end
class User
validates :email email: true
end
如果使用的是validate而非validate_each就必須先include並且用validates_with來驗證。
class User
include ActiveModel::Validations
validates_with EmailValidator
end
class EmailValidator < ActiveModel::Validator
def validate(record)
# Logic to check email is valid or not
record.errors.add :email, "This is some complex validation"
end
end
回呼 CallBack
資料驗證及回呼
回呼可以在Model資料的生命週期,掛載事件上去,例如我們可以在資料儲存進資料庫前,做一些修正,或是再儲存成功之後,做一些其他動作。
當一個物件儲存時的流程如下:其中有before/after的地方就是回呼的觸發時機。
save > valid >
before_validation >
validate >
after_validate >
before_save >
before_create >
create >
after_create >
after_save >
after_commit
例如:before_validation常用來清理資料或設定預設值:
class Event < ApplicationRecord
before_validation :setup_defaults
protected
def setup_defaults
self.name.try(:strip!) # 把前後空白去除
self.description = self.name if self.description.blank?
self.is_public ||= true
end
end
參考資料:
Rails實戰聖經:資料驗證及回呼
Building Custom Validators in Rails