Skip to content

Ror Validations

DodaTech 4 min read

title: Ruby on Rails Validations — Complete Guide to Data Validation description: 'Learn Ruby on Rails validations: built-in validators, custom validation methods, conditional validation, error messages, and model-level data integrity rules.' date: 2026-06-28 lastmod: 2026-06-28 weight: 20 tags: [backend, ror]


Rails validations ensure data integrity at the model layer, checking data before it reaches the database with built-in helpers and custom validation methods.

## What You'll Learn

By the end of this tutorial, you'll use Rails' built-in validators (presence, uniqueness, length, format), create custom validations, validate associations, display errors in views, and understand validation contexts.

## Real-World Use

A User model with validates :email, presence: true, uniqueness: true, format: { with: URI::MailTo::EMAIL_REGEXP }. Invalid registrations show field-level error messages to the user.

## Validations Learning Path

```mermaid
flowchart LR
  A[Migrations] --> B[Validations]
  B --> C[Associations]
  C --> D[Forms]
  D --> E[Authentication]
  B --> F{You Are Here}
  style F fill:#f90,color:#fff

Built-in Validators

class User < ApplicationRecord
  validates :email, presence: true
  validates :email, uniqueness: { case_sensitive: false, message: "already taken" }
  validates :username, length: { minimum: 3, maximum: 30 }
  validates :password, length: { in: 8..128 }
  validates :age, numericality: { only_integer: true, greater_than_or_equal: 18 }
  validates :website, format: { with: /\Ahttps?:\/\/.*\z/, allow_blank: true }
  validates :terms, acceptance: true
  validates :role, inclusion: { in: %w[user admin moderator] }
  validates :email, confirmation: true
end

Custom Validation Methods

class Post < ApplicationRecord
  validate :title_not_all_caps
  validate :body_has_minimum_words

  private

  def title_not_all_caps
    if title.present? && title == title.upcase
      errors.add(:title, "cannot be all uppercase")
    end
  end

  def body_has_minimum_words
    if body.present? && body.split.length < 10
      errors.add(:body, "must contain at least 10 words")
    end
  end
end

Custom Validator Class

# app/validators/email_format_validator.rb
class EmailFormatValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    unless value =~ /\A[^@\s]+@[^@\s]+\.[^@\s]+\z/
      record.errors.add(attribute, (options[:message] || "is not a valid email"))
    end
  end
end

class User < ApplicationRecord
  validates :email, email_format: true
end

Conditional Validation

class Order < ApplicationRecord
  validates :credit_card_number, presence: true, if: :paid_by_card?
  validates :shipping_address, presence: true, unless: :digital_only?

  # With Proc
  validates :discount_code, presence: true, if: -> { total > 100 }

  # With multiple conditions
  with_options if: :paid_by_card? do |order|
    order.validates :credit_card_number, presence: true
    order.validates :expiry_date, presence: true
    order.validates :cvv, presence: true
  end

  private

  def paid_by_card?
    payment_method == "card"
  end

  def digital_only?
    line_items.all?(&:digital?)
  end
end

Error Messages

# Customizing error messages
validates :name, presence: { message: "is required" }
validates :email, format: { with: /\A.*@.*\z/, message: "must be a valid email address" }

# I18n error messages (config/locales/en.yml)
# activerecord:
#   errors:
#     models:
#       user:
#         attributes:
#           email:
#             blank: "Email address is required"
#             taken: "This email is already registered"

Common Mistakes

1. Database-Level Only Validation

Rails validations run at the model level. Use database constraints (NOT NULL, UNIQUE) as a safety net.

2. Over-Validating

Too many validations make models hard to maintain. Validate what matters for data integrity, not everything.

3. Not Handling Validation in Controllers

Always check if @model.save or @model.valid? before proceeding. Return errors to the user on failure.

4. Using validates_associated Improperly

validates_associated can cause infinite loops if both models validate each other.

5. Skipping Validation for Performance

Bulk inserts skip validations (insert_all!). Ensure data is clean when bypassing validations.

Practice Questions

1. What is the difference between presence and existence validators?

presence checks the attribute is not empty/nil. existence isn't a built-in; uniqueness checks uniqueness in the DB.

2. How do you create a custom validator?

Create a class inheriting from ActiveModel::EachValidator and implement validate_each, or use validate :method_name.

3. How do you show validation errors in a view?

Use @model.errors.full_messages or @model.errors[:attribute] in the view. form_with shows errors automatically.

4. What is conditional validation?

Validations that only run when a condition is met (if/unless with symbol, Proc, or method).

5. Challenge: Create a model with 5 different validations including a custom one.

class Product < ApplicationRecord
  validates :name, presence: true, length: { maximum: 100 }
  validates :price, numericality: { greater_than: 0 }
  validates :sku, uniqueness: true, format: { with: /\A[A-Z]{3}-\d{4}\z/ }
  validate :price_must_be_reasonable
  private
  def price_must_be_reasonable
    if price.present? && price > 10_000
      errors.add(:price, "must be under $10,000")
    end
  end
end

FAQ

Are Rails validations enough for data integrity?

Combined with database constraints (migrations), they provide excellent data integrity. Use both.

How do I skip validations?

Use save(validate: false), update_attribute, or insert_all for bulk operations.

What is validates_associated?

Validates the associated records. Useful for validating nested attributes.

How do I validate on create only?

validates :password, length: { minimum: 8 }, on: :create.

Can I have context-specific validations?

Yes. validates :email, presence: true, on: :account_setup. Pass context: :account_setup when saving.

Mini Project: Product Validations

Create a Product model with comprehensive validations.

class Product < ApplicationRecord
  validates :name, presence: true, length: { in: 2..200 }
  validates :price, numericality: { greater_than: 0, less_than: 10_000 }
  validates :sku, presence: true, uniqueness: true
  validates :category, presence: true
  validates :description, length: { minimum: 20 }, if: :published?
  validate :price_matches_category
end

What's Next

Ruby on Rails Associations Ruby on Rails Forms

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro