2011-01-28 49 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?}