perform one validation only if all other validations pass

11,333

Solution 1

You could check the errors array and return.

def check_valid_bank_account
  return unless errors.blank?
  …
end

Solution 2

I would actually recommend taking this code out of a validation method and putting it into a separate "valid_bank_account?" method that you can call manually when you actually want to hit the API, especially because it's an expensive operation. Some reasons for this behavior are that you might not want to run this validation if the account number has not changed or if you are only updating the record.

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

It's more tedious but it ensures that you have control over when the validation actually occurs.

Solution 3

use something like this

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

also a Proc should work here too

validate :check_valid_bank_account, :if => Proc.new{|object| object.errors.empty?}
Share:
11,333
aaronrussell
Author by

aaronrussell

Updated on June 07, 2022

Comments

  • aaronrussell
    aaronrussell almost 2 years

    I am building a custom validation that checks a bank account number and sort code with an external API to test if they exist (i.e. is a proper valid UK bank account). As this is an expensive operation I don't want to bother hitting the API unless the account number and sort code pass Rails' built in validations.

    For example, I have these basic validations:

    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
    

    Then I have my custom validation:

    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
    

    What I want to ensure is that the custom validation is only performed if the rest of the model is valid. No point paying 25p to be told no account number was provided when I can work that out myself!

    I am aware I could write some logic that checks that the two attributes are not blank and matches them against the regex manually... but that doesn't seem a very Rails way.