Validations In Rails Using Active Record
Published: 2023-01-17 20:10:41

What is a validation in active Ruby rails?
Validations are unique methods used in rails to prevent invalid data from getting to our database. We can think of validation as a bouncer in a nightclub. The bouncer checks your ID, ensures your age is correct, and allows you to enter the nightclub. In the same way, the bouncer ensures you are suited to get into the club, and validations ensure the data sent to the database is valid before the database is updated.

A validation is like any other ruby macro, such as attr_accesor, has_many or belongs_to. The first argument in a validation is the name of the attribute that needs to be validated. The second argument is a hash of options that guarantees our attribute will be validated. Let's check that out in the code below.
```
class User < ActiveRecord::Base

  validates :birth_date, :presence => true
  validate :validate_age

  private

  def validate_age
      if birth_date.present? && birth_date > 21.years.ago.to_d
          errors.add(:birth_date, 'You should be over 21 years old.')
      end
  end
end
```
In the above example, we have two validates macros. The first one is checking to ensure that our user has a birthdate. The second validate macro ensures the user is above 21 years old. Similar to a bouncer checking for your age to let you into the nightclub. If validations fail, the user is not allowed into the nightclub or, for our programming purposes, the database.
Assuming our user controller runs a .create or a .update method with information from our client side on a user1 instance. When user1.create is run, the first two lines of code to run come from our validates method in our user model.

The ActiveRecord method of validates in our user's controller will only allow user1 to be copied to the database if user1 has a birthday and the birthday makes user1 older than 21. If we run user1.errors.messages, we will see all the errors associated with the user1 instance. 

The magic that rails has to offer continues. The client-side significantly benefits from how to handle the errors that rails invalidated. The client-side requested that user1  be created. Our validations prevented user1 from being created into our database because their birthday needed to be provided or their age a minimum of 21. Since we are working with a "model view controller" in rails. Our controller needs to know how to handle erroneous messages. We can use the rescue method to return our error messages to the client-side.
```
#app/controllers/travelers_controller.rb
class TravelersController < ApplicationController
  # The exception class lets us run the record method on the ActiveRecord 
  # instance and call the private method :render_invalid_response.
  #  It will rescue all invalid exceptions raised in this controller.
  rescue_from ActiveRecord::RecordInvalid, with: :render_invalid_response

  # the create! method will attempt to save the newly created instance to the
  # DB but if it fails an exception will be raised handled by the rescue_from
  def create
    user1 = User.create!(params)
    render json: user1, status: created
  end
  private

  # this private method will run only when an invalid exception is raised,
  # the invalid variable is the instance of the exception class and includes
  # the message from the model validation that failed 
  def render_invalid_response(invalid)
    render json: { errors: invalid.record.errors }, 
      status: :unprocessable_entity
  end
end
```
The RecordInvalid exception class macro is constantly looking for invalid exceptions to be raised anywhere in the user's controller. When an invalid exception is raised, an invalid instance variable will be provided as an argument to the :render_invalid_response method. The exception is provided from the model and attached to the invalid variable.

The create action in the controller uses an exception handler. The bang or "!" is shown after the create method. If the validations trigger an exception, the rescue_from method response will trigger instead of user1 being returned to the client side. The client side will then render JSON with a key of errors. We can then retrieve the errors using the record method, which ActiveRecord also provides.