Active Record Validations

Introduction

Validation Methods


class Person < ActiveRecord::Base
  def validate
  end

  def validate_on_create
  end

  def validate_on_update
  end
end

Validation Callbacks


class Person < ActiveRecord::Base
  validate :check_n_subjects
  validate_on_update :check_n_geographic_areas
  validate_on_create :check_emails_valid

  def check_n_subjects    
    errors.add(:subjects, "too many subjects") if subjects.size > 7
  end  
  def check_n_geographic_areas
  end  
  def check_emails_valid  
  end
end

ActiveRecord::Base#valid?


def valid?
  errors.clear
  run_callbacks(:validate)
  validate
  if new_record?
    run_callbacks(:validate_on_create)
    validate_on_create
  else
    run_callbacks(:validate_on_update)
    validate_on_update
  end
  errors.empty?
end

Saving without validation


person = Person.find(5)
person.age = -5
person.save(false) # saves without validation
person.update_attribute(:age, -5) # saves without validation

Validation Macros


validates_acceptance_of
validate_associated
validates_confirmation_of
validates_each
validates_exclusion_of
validates_format_of
validates_inclusion_of
validates_length_of
validates_numericality_of
validates_presence_of
validates_size_of
validates_uniqueness_of

Validation Macros: Usage


class User < ActiveRecord::Base
  validates_presence_of :name, :email, :password
  validates_format_of :name,
    :with => /^\w+$/,
    :message => "may only contain word characters" 
  validates_uniqueness_of :name,
    :message => "is already in use" 
  validates_length_of :password,
    :within => 4..40
  validates_confirmation_of :password
end

Validation Macros: More Usage


class User < ActiveRecord::Base
  validates_inclusion_of :role,
    :in => %w(super admin user),
    :message => "must be super, admin, or user",
    :allow_nil => true
  validates_presence_of :customer_id,
    :if => Proc.new { |u| %w(admin user).include?(u.role) }
  validates_numericality_of :weight,
    :only_integer => true,
    :allow_nil => true,
    :greater_than => 0,
    :less_than => 500
end

Validation Error Messages


class Person < ActiveRecord::Base
  validates_uniqueness_of :name
end

peter = Person.create(:name => "Peter")
peter2 = Person.create(:name => "Peter")
peter2.valid? # => false
peter2.errors.on(:name) # => "has already been taken" 
peter2.errors.full_messages # => ["Name has already been taken"]