DEV Community

Cover image for Introducing Validations
Rachel Stark
Rachel Stark

Posted on • Edited on

Introducing Validations

Active Record validations allow you control data saved to your database and help prevent headaches down the road! From a properly formatted date... to making sure a username is unique upon signup, Active Record provides pre-defined helpers you can use to make sure the input meets requirements. Let's take a look at some common validations that help keep your database tables cohesive.

diagram showing validations to database

There are a few ways you can provide validations for data but the most efficient way is by using them server side at the model level. Model level validations are database agnostic (compatible with any database), cannot be bypassed by the end users, and are easy to test and maintain. Now that being said, there are benefits to having both server side and client side validation! It can improve application performance by not having to process invalid data. To get the grasp of the differences and benefits of using both, check out this article.

So where in the process do validations take place? Active Record validations allow us to validate data before being stored in our database. They are triggered when using the create, save and update methods. The validations run right before the SQL commands are sent to the database, so if any fail, Active Record will not perform the SQL INSERT or UPDATE. If the record is invalid, create returns the object, save and update return false, and all the bang versions of these methods raise an exception. (e.g. create!) Here is a list of methods that skip validations.


presence and absence validation helper headerThe presence helper makes sure that the specified attribute(s) are not empty. A nil or a blank string value will be invalid.

class Student < ApplicationRecord
  validates :name, :grade, presence: true
end
Enter fullscreen mode Exit fullscreen mode

In the example above, Active Record will not create a new student without a name and grade. The direct opposite helper is absence, which will make sure the attribute(s) are nil or a blank string.


uniqueness validation helper headerIt's common to need a unique attribute value, for example, you would probably want unique usernames for your application. Here the helper will search the Student table for existing records to determine the uniqueness of the specified attribute.

class Student < ApplicationRecord
  validates :username, uniqueness: true
end
Enter fullscreen mode Exit fullscreen mode

There is a scope option available with uniqueness that allows you to specify additional columns to consider when checking for uniqueness.

class Assignment < ApplicationRecord
  belongs_to :student
  validates :title, presence: true, uniqueness: { scope: :student_id }
end
Enter fullscreen mode Exit fullscreen mode

This is requiring that the combination of the assignment title and student_id be unique. Other student accounts can have the same assignment title, but it will not be duplicated in any student account.


length validation helper header There are many options for validating the length of an attribute's value...

class Student < ApplicationRecord
  validates :name, length: { minimum: 5 } # sets minimum
  validates :bio, length: { maximum: 500 } # sets maximum
  validates :password, length: { in: 5..12 } # provides a range
  validates :library_number, length: { is: 8 } # must match length
end
Enter fullscreen mode Exit fullscreen mode

You can customize error messages using default error messages :wrong_length, :too_long, and :too_short. Note that the default messages are plural(e.g. 'characters'). There is also %{count} which is a placeholder for the number constraint being used.

class Student < ApplicationRecord
  validates :bio, length: { maximum: 500,
    too_long: "%{count} characters is the maximum allowed" }
  # sets maximum, custom message specifying the character limit
end
Enter fullscreen mode Exit fullscreen mode


format validation helper headerYou might need to format strings for your application, in which case, you can test if they match specifications given using the :with option. This can come in handy to check that a valid email address is entered or if you wanted to exclude numbers/symbols.

class Student < ApplicationRecord
  validates :name, format: { with: /\A[a-zA-Z]+\z/,
    message: "only allows letters" }
end
Enter fullscreen mode Exit fullscreen mode


numericality validation helper header This helper ensures attributes have only numeric values. To specify only integer numbers, use :only_integer set to true. The numericality helper does not allow nil values. To allow for this option you can use allow_nil: true.

class Test < ApplicationRecord
  validates :score, numericality: { only_integer: true }
end
Enter fullscreen mode Exit fullscreen mode

:greater_than
:greater_than_or_equal_to
:equal_to
:less_than
:less_than_or_equal_to
:other_than (value must be other than the supplied value)
:in (value must be in the supplied range)
:odd
:even


comparison validation helper header This helper compares two values and will validate only if the comparison is true. Below the validation requires the race :start_time to be :less_than the :finish_time or it will be invalid.

class Race < ApplicationRecord
  validates :start_time, comparison: { less_than: :finish_time }
end
Enter fullscreen mode Exit fullscreen mode

These are the supported options for comparison:
:greater_than
:greater_than_or_equal_to
:equal_to
:less_than
:less_than_or_equal_to
:other_than (value must be other than the supplied value)


Before I wrap up, I wanted to demonstrate some of the many ways you can check your validations using the rails console:

class User < ApplicationRecord
  validates :username, presence: true
end
Enter fullscreen mode Exit fullscreen mode
$ rails console

>> user1 = User.create(username: "")
=> #<User id: nil username: nil, created_at: nil, updated_at: nil>
#create returns the object with no id assigned, meaning it did not save to the database

>> user1.save
=> false

>> user2 = User.create!(username: "")
=> ActiveRecord::RecordInvalid (Validation failed: Username can't be blank)
#using the bang operator with create raises an exception when invalid

>>user3 = User.create(username: "Thor").valid?
=> true

>>user1.valid?
=> false
#you can use the opposite .invalid? 

>>user1.errors.any?
=> true
>>user1.errors.full_messages
=>  ["Username can't be blank"] 
Enter fullscreen mode Exit fullscreen mode

I only scratched the surface on what's possible using Active Record validations! Explore more pre-built helpers, conditional and custom validations, and validation errors.

database with text so fresh and so clean clean

You can connect with me on LinkedIn & GitHub

Resources: Rails Guides - Active Record Validations

Top comments (0)