Sitemap
Suman Awal

Suman Awal

Custom ActiveRecord Validator

2 min readNov 11, 2021

Active Record validation is one of the impartial magic in Rails. These validations are used to ensure only valid data are forwarded to the database. Validations are usually placed on the model that makes it easily testable and maintainable. Here is an example of validation that validates the field as numerical.

validates :age, numericality: { only_integer: true }

ActiveRecord validators are really easy and simple to understand. Even though Rails provides the utmost validations, sometimes we need to have our own validator based on our business logic and the application-specific validations. Let’s take an example of an application where the business is specific to Nepal and the user needs a Nepalese phone number. The business requirement is that the phone number must be valid only if it matches the criteria for a Nepalese phone number. This requirement can be fulfilled by adding the custom validation in the model defining a method to validate the input as follows:

validate :nepal_phone_number?def nepal_phone_number?
return if phone_number =~ /^(?:\+?977)\d{10}\z/
errors.add(:phone_number, “must be a valid Nepalese phone number”)
end

The above method adds an error and prevents saving data in the database if the number does not satisfy the regex for the Nepalese phone number. This is perfect but sometimes application needs the same validations in multiple places. For eg, the phone number validations might be required in the client number, a contact person number, and so on. We can definitely keep the method in the module and include it in each model as required if the field name is the same or with some tweaks for the different field names. Here comes the role of Active Record Custom Validator.

Get Suman Awal’s stories in your inbox

Join Medium for free to get updates from this writer.

We can create a custom validator file inside the validators folder as follows:

# api/validators/nepalese_phone_number_validator.rbclass NepalesePhoneNumberValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
return unless value.present?
unless value =~ /^(?:\+?977)\d{10}\z/
record.errors.add(attribute, “must be a valid Nepalese phone number”)
end
end

This validator can be easily integrated into any field that requires to be the Nepalese phone number.

validates :phone_number, nepalese_phone_number: true

This approach really helps to keep the code clean and maintainable in the large app where we need to validate different fields in different ways based on the business need. Happy Coding!!

--

--