Posted about 4 years ago. Visible to the public.

Rails: How to check if a certain validation failed

If validations failed for a record, and you want to find out if a specific validation failed, you can leverage ActiveModel's error objects.
You rarely need this in application code (you usually just want to print error messages), but it can be useful when writing tests.

As an example, consider the following model which uses two validations on the email attribute.

Copy
class User < ApplicationRecord validates :email, presence: true, uniqueness: true end

Accessing errors

Let's assume we have a blank user:

Copy
user = User.new user.valid? # => false

The record's errors then contains all validation errors.

Copy
>> user.errors => #<ActiveModel::Errors [#<ActiveModel::Error attribute=email, type=blank, options={}>]>

You can access errors[:email] to get the error message itself ("can't be blank").
However, your code may be more robust and readable if you check for the error type itself.

You can use the added? Archive or of_kind? Archive methods for that.

Copy
>> user.errors.added?(:email, :blank) => true
Copy
>> user.errors.of_kind?(:email, :blank) => true

Note how error types don't necessarily match the validation name (e.g. :blank for :presence, :taken for :uniqueness).

Difference between added? and of_kind?

While added? might feel more natural to use, it behaves differently than of_kind? because it also compares options from the validation error. of_kind? does not do that.

This is is relevant for validations that provide extra context, like length or uniqueness validations.

Consider a User that can not be saved because there already is a record with the same email address.

Copy
user = User.new(email: "user@example.com") user.valid? # => false
Copy
>> user.errors => #<ActiveModel::Errors [#<ActiveModel::Error attribute=email, type=taken, options={:value=>"user@example.com"}>]>

If you do not care about the options, use of_kind?:

Copy
>> user.errors.of_kind?(:email, :taken) => true

Using added? without specifying options will return false:

Copy
>> user.errors.added?(:email, :taken) => false
Copy
>> user.errors.added?(:email, :taken, value: "user@example.com") => true

Most often, you probably want to use of_kind?.

makandra has been working exclusively with Ruby on Rails since 2007. Our laser focus on a single technology has made us a leader in this space.

Owner of this card:

Avatar
Arne Hartherz
Last edit:
10 days ago
by Arne Hartherz
Keywords:
ActiveRecord, ActiveModel, attributes, fields, errors
About this deck:
We are makandra and do test-driven, agile Ruby on Rails software development.
License for source code
Posted by Arne Hartherz to makandra dev
This website uses short-lived cookies to improve usability.
Accept or learn more