iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 26
1
自我挑戰組

毫無基礎學習 Ruby on Rails 的 甘苦心得系列 第 26

DAY 26 Rails Validators / 回呼Callback

除了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


上一篇
DAY 25 資料庫( SQL ) 建立表格 欄位介紹
下一篇
DAY 27 PORO
系列文
毫無基礎學習 Ruby on Rails 的 甘苦心得30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言