RoR Active Record Validations

This tutorial will teach you how to validate the state of objects before they are sent to the database using Active Record’s validation feature.

After reading the guide, you will know:

How to use the built-in Active Record validation helpers

How to create your own validation methods

How to deal with error messages generated during validation

Overview of validations

Here is an example of a very simple validation:

classPerson < ApplicationRecord

  validates :name, presence: true

end

Person.create(name: “John Doe”).valid? # => true

Person.create(name: nil).valid? # => false

As you can see, our validation lets us know that our Person is not valid without the name attribute. The second Person will not be saved to the database.

Before diving into the details, let’s talk about how validations fit into the big picture of an application.

Why use validations?

Validations are used to make sure that only valid data is saved to your database. For example, it may be important for your application that each user provides a valid email and postal address. Model-level validations are the best way to ensure that only valid data is stored in the database. They are database independent, cannot be bypassed by end users, and are easy to test and maintain. Rails introduces ease of maintenance, provides built-in helpers for common needs, and allows you to create your own validation methods.

There are several ways to validate data before it is stored in your database, including constraints built into the database, client-side validations, and controller-level validations. Briefly about the pros and cons:

Database constraints and/or stored procedures make validation mechanisms dependent on the database, making testing and maintenance more difficult. However, if your database is being used by other applications, database-level validation can safely handle some things (such as uniqueness in loaded tables) that would be difficult to do otherwise.

Client-side validations can be very useful, but generally unreliable when used alone. If they use JavaScript, they may be skipped if JavaScript is disabled in the client browser. However, when combined with others, front-end validations can be a convenient way to provide users with immediate feedback when using your site.

Controller-level validations are tempting to do, but this often leads to cumbersome and difficult testing and maintenance. Whenever possible, keep your controllers ‘skinny’ so your application will be nice to work with in the long run.

Choose them for your specific specific tasks. The general consensus of the Rails team is that model-level validations are the best option in many cases.

When does validation take place?

There are two types of Active Record objects: those that match a row in your database, and those that don’t. When you create a new object, for example using the new method, that object is not yet bound to the database. As soon as you call save, this object will be saved to the appropriate database table. Active Record uses the new_record? to determine if the object is already in the database or not. Consider the following simple Active Record class:

classPerson < ApplicationRecord

end

You can see how it works by looking at the rails console output:

$ bin/rails console

>>p = Person.new(name: “John Doe”)

=> #<Person id: nil, name: “John Doe”, created_at: nil, updated_at: nil>

>>p.new_record?

=> true

>>p.save

=> true

>>p.new_record?

=> false

Creating and saving a new record sends an SQL INSERT operation to the database. An update to an existing record sends an UPDATE SQL operation instead. Validations usually run before these commands are sent to the database. If any of the validations fail, the object is marked invalid and Active Record does not perform the INSERT or UPDATE operation. This helps to avoid storing an invalid object in the database. You can choose to run specific validations when an object is created, saved, or updated.

CAUTION: There are different methods for changing the state of an object in a database. Some methods cause validations, some do not. This means that it is possible to save an object with an invalid status to the database if you are not careful.

The following methods invoke validation, and save the object to the database only if it is valid:

create

create!

save

save!

update

update!

Versions with an exclamation mark (i.e. save!) throw an exception if the entry is invalid. The non-exclamatory versions don’t call: save and update return false, create returns an object.

valid? or invalid?

Before saving an Active Record object, Rails runs your validations. If the validations produce any errors, Rails does not save this object.

You can also run these validations yourself. valid? calls your validations and returns true if no errors were found on the object, false otherwise.

classPerson < ApplicationRecord

  validates :name, presence: true

end

Person.create(name: “John Doe”).valid? # => true

Person.create(name: nil).valid? # => false

After Active Record performs validations, any errors it finds will be available in the errors.messages instance method, which returns a collection of errors. By definition, an object is valid if this collection is empty after validations have been run.

Note that an object created with new does not report errors, even if technically invalid, because validations are only automatically run when the object is saved, as is the case with the create or save methods.

classPerson < ApplicationRecord

  validates :name, presence: true

end

>> p = Person.new

# => #<Person id: nil, name: nil>

>>p.errors.messages

# => {}

>>p.valid?

# => false

>>p.errors.messages

# => {name:[“can’t be blank”]}

>>p=Person.create

# => #<Person id: nil, name: nil>

>>p.errors.messages

# => {name:[“can’t be blank”]}

>>p.save

# => false

>>p.save!

# => ActiveRecord::RecordInvalid: Validation failed: Name can’t be blank

>>Person.create!

# => ActiveRecord::RecordInvalid: Validation failed: Name can’t be blank

invalid? it’s just the opposite of valid?. It runs your validations, returning true if errors have been added to the object and false otherwise.

errors[]

To check whether or not a particular attribute of an object is valid, you can use errors[:attribute] which returns an array with all of the attribute’s errors, when there are no errors for a particular attribute, an empty array is returned.

This method is only useful after the validations have been run, as it only examines the errors collection, but does not invoke the validation itself. It differs from the ActiveRecord::Base#invalid? method described above in that it does not check the validity of the object as a whole. It only checks what errors were found for a particular object attribute.

Leave a Reply

Your email address will not be published.