如果所有其他验证都通过,则仅执行一次验证

29

我正在构建一个自定义验证器,它会使用外部API来验证银行账号(bank account number)和排序码(sort code)是否存在(即是否是合法的英国银行账户)。由于这是一项昂贵的操作,我不想在账号和排序码未通过Rails内置验证时打扰API。

例如,我有以下基本验证:

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的风格。

3个回答

35
你可以检查errors数组并返回。
def check_valid_bank_account
  return unless errors.blank?
  …
end

2
如果在其他验证之前运行check_valid_bank_account验证,我认为这不会起作用。 - Pan Thomakos
4
验证是按照定义的顺序运行的,因此这取决于定义的顺序。 - edgerunner
1
这对我有用,但是有没有其他方法来做同样的事情? - digitalWestie
我同意@digitalWestie的观点。这更像是仓促的解决方案。 - jibiel

9

我建议将此代码从验证方法中提取出来,放入一个单独的“valid_bank_account?”方法中,当您实际想要调用API时再手动调用它,特别是因为这是一项昂贵的操作。这种行为的一些原因是,如果帐户号码没有更改或者您仅更新记录,则可能不希望运行此验证。

def save_only_with_valid_bank_account
  如果 @account.valid? && @account.valid_bank_number? && @account.save
   ...
  end
end

虽然更加繁琐,但它确保您对验证何时发生拥有控制权。


5
使用类似于这个的东西。
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?}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接