Introduction to Active Record callbacks and validations

Mateo mojica
7 min readAug 12, 2022

--

Photo by Markus Spiske on Unsplash

During the normal operation of a Rails application, objects may be created, updated, and destroyed. Active Record provides hooks into this life cycle so you can control the way your application handles its data.

There are several ways to achieve this, but Active Record provides built-in methods that help you with these tasks without the need for any or very little additional code. There are some concepts that we have to get familiar with to start using them.

The first one is validations. Validations are used to ensure that only valid data is saved into your database. There are several ways to validate data before it is saved, including native database constraints, client-side validations, controller-level validations, and model-level validations. This time we are going to focus on model-level validations since that is one of the functionality that Rails provides out of the box.

Active Record has a particular way to handle data in the database. When you create a new object of a model or update an existing one, either with the new & save combination, with the create or with the update method, rails doesn’t insert that object immediately into the database, it performs all kinds of validations on that object before sending the queries, only after those checks pass, both made by the user and Active Record itself, the SQL INSERT or SQL UPDATE command is performed on the database. If the checks do not pass then the object is marked as invalid and the SQL commands are not performed.

With validations, you can choose which operation triggers which validation. The following methods trigger validations, and will save the object to the database only if the object is valid: create, create!, save, save!, update, update_attributes, update_attributes!.

Photo by Markus Spiske on Unsplash

Let’s pause for a second and talk about the methods that have a bang(!) on them. With a regular method, you have to verify if the object is valid and if there are any errors after the method is called. With the bang methods, you don’t have to do this since they will raise an exception if there was a problem when running and continue as planned if everything was successful, this will make your code less cluttered and more readable, just remember to catch the exception. This will help with the bubbling-up method of catching errors that allow errors to be handled by the upper methods of the calling stack in one place instead of having to handle errors in each step of the calling stack.

Keep in mind that some methods skip validations altogether, so be very careful when using them: decrement!, decrement_counter, increment!, increment_counter, toggle!, touch, update_all, update_attribute, update_column, update_counters and the save method when you pass the :validate=>false attribute to it.

Photo by Hello I'm Nik on Unsplash

Active Record has many pre-defined helpers that you can use inside the class definition of your model. Every time a validation fails an error gets added to the error object associated with the validated attribute. The helpers don’t have a limit on the number of attributes that can be checked, in case you want to bundle several attributes under the same check. All the helpers can take the :on option, to select which method (save, create or update) the validations get triggered and the message: option, to specify the message that is going to be stored in the error object. The most used validations are:

  • format: This helps validate attributes against a given regular expression, which is specified by the option :with. The default message is “is invalid”.
  • inclusion: Is the opposite of exclusion, and validates that the values of the attribute are within the specified set of values.
  • length: This one helps to validate the length of an attribute. It takes different options according to the needs: :minimum, :maximum, :in or :within to give a range, and :is to specify a value. You also have options for the messaging depending if it is too long or too short.
  • numericality: This is used to check if an attribute is a number. By default, it checks if it has a sign and accepts integers or floats as well, but if you want to check for it to be an integer use the option :only_integer and set it to true.
  • presence: This validates that an attribute is not empty. The default message is “can’t be empty”.
  • uniqueness: It checks that the attribute value is unique before saving it, but it is not a replacement for a uniqueness constraint in the database, so if you happen to have 2 active connections to the database, this may cause that you will have the same value for 2 records.
  • validates_with: Passes the record to a different class for validation.

Other validations are:

  • acceptance: This is used for a field that requires an acknowledgment from the user, like the terms and conditions or the user agreement on some sites. It takes the :accept option to have a specific value to be considered as accepted, the default is true. The default message is “must be accepted”.
  • validates_associated: This is used when the model has other associations that also need to be validated. It won’t mark it as valid until all the associations are valid as well. The default message is “is invalid”.
  • confirmation: This should be used when you have two fields that should contain the same information, like the password in a password change form. This helper understands that the name of the attribute followed by a _confirmation is the field that the attribute should be compared to. This works better with pages that are rendered by rails itself using ERB.
  • exclusion: This helper validates the attributes are not in a given set. The set can be any enumerable object. It has the option :in that receives the set of values that won’t be accepted for the attribute.
  • validates_each: validates the attributes against a block.
Photo by Glenn Carstens-Peters on Unsplash

The second concept that we are going to learn is callbacks. Callbacks are methods that get called at certain moments of an object’s life cycle. With callbacks, it is possible to write code that will run whenever an Active Record object is created, saved, updated, deleted, validated, or loaded from the database. The most important callback is the “before_validation”, this one runs before any validation on the object is performed, which means that any value that you change or add to the object will get validated within the object’s validations. But in case you don’t need to validate anything or just check something in another moment of the life cycle, these are the other callbacks that are available: after_validation, before_save, around_save, before_create, around_create, after_create, after_save, before_update, around_update, after_update, before_destroy, around_destroy, after_destroy. The destroy ones are very useful to ensure that nothing is depending on the object that is being destroyed or to perform clean-up of unnecessary things that the model uses. The same methods that skip validations, also skip callbacks so have that present when you use them.

Sometimes you need to run your callbacks or validations only when a certain condition is met, for this you can use the :if and :unless options to make them conditional on the satisfaction of a given process. For this check, you can create your methods, but rails comes with a series of “dirty attribute methods” that help you to control better certain aspects of the object status. These methods are: attribute_before_last_save, attribute_change_to_be_saved, attribute_in_database, attributes_in_database, changed_attribute_names_to_save, changes_to_save, has_changes_to_save?, reload, saved_change_to_attribute, saved_change_to_attribute?, saved_changes, saved_changes?, will_save_change_to_attribute?. All of these methods will help you, for example, to know if a specific attribute has changed and should trigger some action. Please refer to the documentation for more information on how to use these methods.

Photo by Alina Grubnyak on Unsplash

In some applications, the built-in validations are not enough for the needs of the project, in these cases rails let you write your validator classes or validator methods. Validators are classes that extend the ActiveModel::Validator class. These classes must implement a validate method that takes a record as an argument and performs the validation on it. The custom validator class is called using the validates_with method and must include the ActiveModel::Validations as well for it to work.

Validator methods are instance methods that verify the state of your model and add messages to the error object when they are invalid. To use them you have to register them in the class with the method validate and the names of the methods as symbols.

This is just a glimpse of what you can do with rails validations and callbacks, if you want to learn more I invite you to read the articles linked in the references or visit the ruby guides for more in-depth information. Thank you for reading this article, if it was useful or you liked it give it a clap and I invite you to read my other articles.

References

--

--

Mateo mojica
Mateo mojica

Written by Mateo mojica

Electronic engineer and software developer

No responses yet