Blog
Tech
Tech
December 12, 2017

Validation Context Behaviour Cheat Sheet (Rails 4)

Validation Context Behaviour Cheat Sheet (Rails 4)

Hello world, this is our first tech blog post :-) We recently encountered some unexpected behaviour with validations and found that most material out there is either shallow or outdated, so we would like to share what we have learned (using Rails v4.2.4 and Ruby v2.3.3.).

Validation contexts in Rails allow you to pick and choose when validations are triggered. But what is actually happening when you call .valid?(:my_context)? It doesn't behave the way you expect...! Here is a cheat sheet, followed by in-depth examples.

Cheat Sheet

Validation triggered?ValidationMethod(without context)on: :createon: :updateon: :admin_area.valid?YesYesYesYes.valid?(:create)YesYesNoNo.valid?(:update)YesNoYesNo.valid?(:admin_area)YesNoNoYes.valid?(:undefined_context)YesNoNoNo

In-depth

You can pick and choose validations with validation contexts. For example, you might only want to run a validation when the object is created: class Appointment < ActiveRecord::Base
validates :starts_in_the_future, on: :create
end
For an overview of validation contexts, see this Arkency post http://blog.arkency.com/2014/04/mastering-rails-validations-contextsYou already use validation contexts in every model. Each time an object is created or updated, Rails secretly validates with the built-in create or update contexts:.valid?(:create) or.valid?(:update).Let's write a custom validation context.A validation statement requiringuniqueness: truetriggers an extra query, when running the validation. We wanted to reduce the number of queries, so we wanted to only check for uniqueness where on create and update.Example validations for our Company model: class Company < ActiveRecord::Base
validates :name, presence: true, uniqueness: true, on: [:create, :update]
validates :name, presence: true, on: :admin_area
validates :address, presence: true
validates :country_of_incorporation, presence: true
end
Use my_company.valid?(:admin_area) to trigger the admin area validation context. Sounds simple, but we managed to find a few gotchas! Let's see what is actually happening with a little quiz.

Quiz: Which validations will be triggered by my_company.valid?(:admin_area)

Not surprisingly they will trigger validations with on: :admin_area: validates :name, presence: true, on: :admin_area
But that's not all there is, it will also run validations without a specified context! validates :address, presence: true
validates :country_of_incorporation, presence: true
Gotcha alert! Be careful with custom validation contexts, as you might accidentally trigger unwanted validations.As I mentioned earlier, the :create and :update validation contexts are built into Rails. What exactly is happening when we create a new Company?

Quiz: Which validations will be triggered by new_company.valid?(:create)

It will trigger validations with on: :create. validates :name, presence: true, uniqueness: true, on: [:create, :update]
And... same here, it will also run validations without a specified context. validates :address, presence: true
validates :country_of_incorporation, presence: true
If you know that :create and :update are the default contexts, the following validations are equivalent: validates :address, presence: true, on: [:create, :update]
validates :country_of_incorporation, presence: true, on: [:create, :update]
However, without this knowledge, it might surprise you. Hence, gotcha alert!Let's come to the plain case of .valid?. What is actually happening here?

Quiz: Which validations will be triggered when we do not specify a validation context my_company.valid?

You might think that a validation that's clearly labeled as on: :admin_area will only be executed under that context. Gotcha alert! A plain valid? will trigger all validations, using the usual Rails validation prioritisation.One more for the gotcha catchers. What happens if you accidentally mistype your context? What if you ask Rails to use a validation context that is not defined?

Bonus round: Which validations will be triggered by valid?(:qwertyuiop) or valid?(:undefined_context)

Gotcha alert!Rails will not raise an error and behave strangely.Rails is blind. It will only trigger validations without a specified context. validates :address, presence: true
validates :country_of_incorporation, presence: true
And Rails ignores all validations with a context!Validation contexts are a powerful tool, but it doesn't always behave as you might expect. If you found this useful to solve your validation puzzle, or if you have feedback, please drop me a line in the comment section.Written by Donna Zhou

Recommended Blog Posts

Explore Taledo

All-in-One Recruiting Solution for Talent Acquisition and Relations

Making the job search easier, faster and more transparent. Explore your potential with Taledo.

People in a meeting
Two people talking
People sitting in a meeting room
A man having a meeting online