This blog is part of our Rails 5 series.

Let’s look at a validation example in Rails 4.x.

class User < ActiveRecord :: Base validates :email , presence: true end >> user = User . new >> user . valid? => false >> user . errors . messages => { :email => [ "can't be blank" ]}

In this case, we do not get any information about the type of failed validation as ActiveModel#Errors only gives the attribute name and the translated error message.

This works out well for normal apps. But in case of API only applications, sometimes we want to allow the client consuming the API to generate customized error message as per their needs. We don’t want to send the final translated messages in such cases. Instead if we could just send details that presence validation failed for :name attribute, the client app would be able to customize the error message based on that information.

In Rails 5, it is now possible to get such details about which validations failed for a given attribute.

We can check this by calling details method on the ActiveModel#Errors instance.

class User < ApplicationRecord validates :email , presence: true end >> user = User . new >> user . valid? => false >> user . errors . details => { :email => [{ :error => :blank }]}

We can also add custom validator types as per our need.

# Custom validator type >> user = User . new >> user . errors . add ( :name , :not_valid , message: "The name appears invalid" ) >> user . errors . details => { :name => [{ :error => :not_valid }]} # Custom error with default validator type :invalid >> user = User . new >> user . errors . add ( :name ) >> user . errors . details => { :name => [{ :error => :invalid }]} # More than one error on one attribute >> user = User . new >> user . errors . add ( :password , :invalid_format , message: "Password must start with an alphabet" ) >> user . errors . add ( :password , :invalid_length , message: "Password must have at least 8 characters" ) >> user . errors . details => { :password => [{ :error => :invalid_format }, { :error => :invalid_length }]}

Passing contextual information about the errors

We can also send contextual data for the validation to the Errors#add method. This data can be later accessed via Errors#details method because Errors#add method forwards all options except :message , :if , :unless , and :on to details .

For eg. we can say that the password is invalid because ! is not allowed, as follows.

class User < ApplicationRecord validate :password_cannot_have_invalid_character def password_cannot_have_invalid_character if password . scan ( "!" ). present? errors . add ( :password , :invalid_character , not_allowed: "!" ) end end end >> user = User . create ( name: 'Mark' , password: 'Ra!ls' ) >> user . errors . details => { :password => [{ :error => :invalid_character , :not_allowed => "!" }]}

We can also use this feature in our Rails 4.x apps by simply installing gem active_model-errors_details.