DEV Community

Tiberius Mairura
Tiberius Mairura

Posted on

Valid? & Invalid? in Ruby

Validation

Have you ever wondered how come your favourite application knew your password is weak or worse, your username is already taken?!

If you have seen those annoying notifications saying you need such and such for your password to qualify, then you have been a victim of validation.

Definition: Validation

To establish the soundness, accuracy, or legitimacy of something.

Record validation in ruby is a mechanism for checking the accuracy of data in your ruby API or application.

Validation is a necessary and extremely significant step to integrate into any meaningful application.

The repercussions of invalid data are far-reaching with devastating blow-ups in business processes, survival, continuity, etc...

Building any thorough validation system is cumbersome and requires one to think out of the box if not at least playing "user" of their application and emulate how extremely a user might tinker with it.

The good news is, in the world of Ruby and Ruby on Rails, validations can be achieved without breaking much of a sweat.

In this article we are going to look at how you can use valid? and invalid? to perform validations in your RoR application.

In Rails, whenever create, create!, save, save!, update, or update! is invoked, validations are triggered. These methods will only save data to the database if the data provided is valid.

It is important to note that validations by default run before the database commands associated with the methods mentioned are sent to the database.

For instance, create which corresponds to SQL's INSERT command will invoke validations on an entity before performing the actual INSERT operation.

In the following steps, I am assuming you have set up your ruby environment and installed the necessary gems for a rails application.

In your terminal run:

rails new validation --api --minimal
Enter fullscreen mode Exit fullscreen mode

The command above will create a new rails project. On successful completion:

Move to the project directory:

cd validations
Enter fullscreen mode Exit fullscreen mode

Open the directory in vs-code:

code .
Enter fullscreen mode Exit fullscreen mode

If everything worked out well, you should have a folder structure similar to this:

Image description

Let us build a Person resource and use it to demonstrate how validations work in rails.

Still on the terminal in the same project folder run:

rails g resource Person name email phone
Enter fullscreen mode Exit fullscreen mode

This command will generate:

  1. Person model
  2. Person controller
  3. routes
  4. Run migrations
  5. Other files are not necessary for this tutorial

Go to

app/models/person.rb

    # app/models/person.rb
    class Person < ApplicationRecord

    end
Enter fullscreen mode Exit fullscreen mode

As you can see, our model does not have any code yet.

On the terminal, let us run: rails c to start an interactive rails console

Image description

Let us create a Person p by running the following command

p = Person.create
Enter fullscreen mode Exit fullscreen mode

On the terminal, you should see this:

Image description

This command ran successfully and we have created one Person!

Let us have a look at the person by running p

Image description

But wait... why is it that the person does not have not any data i.e everything except the id is nil?

Well, running the Person.create triggered an INSERT command which initiated the insert process on our database.

Since we did not have any checks in place to validate our data, the "useless" record was deemed valid and thus accepted and saved without raising any errors or exceptions.

I will leave it to your imagination what will happen if you pull this data and try to display it on your front-end app.

Now let us add some code to our models to constrain the data we receive and permit:

# app/models/person.rb
class Person < ApplicationRecord
  validates :username, presence: true # no blank
  validates :email, presence: true, uniqueness: true # no blank, no duplicates
  validates :phone, length: {is: 10} # must be EXACTLY 10 characters long
end
Enter fullscreen mode Exit fullscreen mode

In the above snippet, we are adding validation to ensure:

  • The entity data must contain a username, not blank
  • It must have an email and the email must be unique
  • The phone number must be exactly 10 digits no more no less

Reload the terminal by running reload!

Try running the same command i.e Person.create again:

Image description

As you can see, this process did not run to completion successfully. This can easily be confirmed by that read error that says rollback transaction which means the entity was not persisted to the database.

Why?

Well, our guards and the validations ensured that we do not allow useless data in our application.

This is what went down:

  1. Run the Peron.create method
  2. Validations are invoked
  3. Check if name is valid => false
  4. Check if email is valid => false
  5. Check if phone is valid => false
  6. Verdict: Invalid object. Do not save!

This means the INSERT command was never invoked.

How did rails know this?

Well, under the hood, every entity has an errors object associated with it.

If the object has any errors, the implication is that that entity is invalid. Otherwise, it is valid.

Let us check out this errors object.

Still, on the terminal, let us run p.errors

Image description

We get the shape of the object but it is not quite readable

Run:

p.errors.full_messages 
Enter fullscreen mode Exit fullscreen mode

Image description

In the screenshot above, we can see the errors that depict validations the entity has violated.

We can argue that since the errors object not empty, the entity is invalid and thus cannot be permited to persist to the database.

valid? and invalid?

As we have learned, validation will be triggered automatically whenever any of the following methods are invoked:

  • create
  • create!
  • save
  • save!
  • update
  • update!

However, we sometimes wish to manually run the validations.

To achieve this, valid? and invalid? are our go-to methods.

valid?

  • This method returns true if an entity is valid and false otherwise.

invalid?

  • This method returns false if an entity is valid and false otherwise.

Both of these methods perform a check on the errors object associated with the entity it was invoked on. If the object has any errors, the valid? return true.

The valid? method returns false to indicate that the entity is invalid and thus cannot be saved to the database. The opposite is true.

How to use valid? and invalid?

Going back to our Person controller, we can add corresponding logic as follows:

class PeopleController < ApplicationController
  def create
     # create person
     person = Person.create(username: params[:username], email: params[:email], phone: params[:phone])

    if person.valid? # if no errors in errors object
      # return user created to the client
      render json: person, status: :created
    else
      # otherwise let them know what went wrong
      render json: {errors: person.errors.full_messages}, status: :unprocessable_entity
    end
  end
end

Enter fullscreen mode Exit fullscreen mode

Let us give it a test drive using Postman

Start by running rails s or rails server on the terminal

Image description

Copy the link http://127.0.0.1:3000 and paste it on Postman address and a /persons and ensure that your Postman interface looks as shown below:

Image description

Here is the sample data I am using:

{
    "username": "hermitex",
    "email": "hermitex@gmail.com",
    "phone": "0765568854"
}
Enter fullscreen mode Exit fullscreen mode

Click on Send

Here is the response:

Image description

Let us try to POST an invalid person

{
    "username": "",
    "email": "hermitex@gmail.com",
    "phone": "0765568854"
}
Enter fullscreen mode Exit fullscreen mode

Notice that we have intentionally sent "" value for username and
repeated the email

By definition, this entity is invalid since our validation logic does not allow duplicate emails and the username must not be blank. Remember?

Let us see what we get.

Image description

There we go!

We have not only successfully prevented an invalid INSERT operation but also responded with appropriate messages and statuses to let the user know what might have gone wrong with their request.

Summary

  • Validation is a way of ensuring data accuracy and integrity
  • In rails validation can be performed using helper methods like validates
  • The following active records methods trigger validations:
    • create
    • create!
    • save
    • save!
    • update
    • update!
  • To trigger validations manually, we can use
    • valid? or
    • invalid?
  • Rails knows whether an entity is valid or not by checking the errors object associated with each entity
  • Presence of an error in the errors object signifies that the object is invalid and valid otherwise

Well, validations can be customized to become complex depending on the use case[s]

Learn more about how this can be done here

Top comments (1)

Collapse
 
teenskeey profile image
Thecodingobare

Awesome article...well structured.