仅在所有其他验证通过时执行一次验证

时间:2011-01-28 16:42:17

标签: ruby-on-rails ruby validation activerecord

我正在构建一个自定义验证,用外部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

我想要确保的是,只有在模型的其余部分有效时才会执行自定义验证。当我能够自己解决这个问题时,没有必要支付25便士的费用!

我知道我可以编写一些逻辑来检查这两个属性是否为空并且手动将它们与正则表达式相匹配......但这似乎不是一种非常Rails的方式。

3 个答案:

答案 0 :(得分:32)

您可以检查errors数组并返回。

def check_valid_bank_account
  return unless errors.blank?
  …
end

答案 1 :(得分:8)

我实际上建议将此代码从验证方法中取出并将其放入单独的“valid_bank_account”中。您实际想要访问API时可以手动调用的方法,尤其是因为这是一项昂贵的操作。此行为的一些原因是,如果帐号未更改或您只是更新记录,则可能不希望运行此验证。

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

这更乏味但它确保您可以控制验证何时实际发生。

答案 2 :(得分: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?}