Ror Validations
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
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