2011-01-28 44 views
25

我建立一個檢查一個銀行帳號排序代碼與外部API定義驗證,如果它們存在測試(即是正確的有效的英國銀行帳戶) 。由於這是一項昂貴的操作,我不想打擊API,除非帳號和排序代碼通過Rails的內置驗證。執行一個驗證只有在其他所有校驗通過

例如,我有這些基本的驗證:

validates_presence_of :sort_code, :account_number 
validates_format_of :sort_code, :with => Regexes::SORT_CODE 
validates_format_of :account_number, :with => Regexes::ACCOUNT_NUMBER 

然後,我有我的自定義驗證:

validate :check_valid_bank_account 

def check_valid_bank_account 
    # code here is irrelevant, but essentially this hits the API 
    # if it's a valid UK bank account all is OK, if not we add an error 
end 

我想要確保的是,自定義驗證只有當其餘的執行的模型是有效的。當我能夠自己解決問題時,沒有人支付25p的費用被告知沒有提供帳號。

我知道我可以編寫一些邏輯來檢查這兩個屬性是不是空白,並手動將它們與正則表達式匹配...但這似乎不是一個非常Rails的方式。

回答

26

您可以檢查errors數組並返回。

def check_valid_bank_account 
    return unless errors.blank? 
    … 
end 
+1

我不認爲如果check_valid_bank_account驗證其他驗證之前運行,這將工作。 – 2011-01-28 16:56:33

8

我實際上會推薦將這段代碼從一個驗證方法中取出並放入一個單獨的「valid_bank_account?」中方法,您可以在實際上想要訪問API時手動調用,尤其是因爲這是一項昂貴的操作。這種行爲的一些原因是,如果帳號沒有更改或者您只更新記錄,則可能不希望運行此驗證。

 
def save_only_with_valid_bank_account 
    if @account.valid? && @account.valid_bank_number? && @account.save 
    ... 
    end 
end 

它更乏味,但它確保您可以控制驗證實際發生的時間。

3

使用這樣的事情

validates_presence_of :sort_code, :account_number 
validates_format_of :sort_code, :with => Regexes::SORT_CODE 
validates_format_of :account_number, :with => Regexes::ACCOUNT_NUMBER 
validate :check_valid_bank_account, :if => :should_i_call_custom_validation? 

def should_i_call_custom_validation? 
    # check for attributes or errors, errors.empty? should work 
end 

也是一個Proc應該在這裏工作太

validate :check_valid_bank_account, :if => Proc.new{|object| object.errors.empty?}