Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

perform one validation only if all other validations pass

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.

like image 418
aaronrussell Avatar asked Jan 28 '11 16:01

aaronrussell


People also ask

What is the difference between validate and validates in rails?

So remember folks, validates is for Rails validators (and custom validator classes ending with Validator if that's what you're into), and validate is for your custom validator methods.

How does validation work in Rails?

Rails validation defines valid states for each of your Active Record model classes. They are used to ensure that only valid details are entered into your database. Rails make it easy to add validations to your model classes and allows you to create your own validation methods as well.

How do I validate in Ruby on Rails?

This helper validates the attributes' values by testing whether they match a given regular expression, which is specified using the :with option. Alternatively, you can require that the specified attribute does not match the regular expression by using the :without option. The default error message is "is invalid".


2 Answers

You could check the errors array and return.

def check_valid_bank_account   return unless errors.blank?   … end 
like image 108
edgerunner Avatar answered Sep 28 '22 06:09

edgerunner


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.

like image 43
Pan Thomakos Avatar answered Sep 28 '22 06:09

Pan Thomakos