module Shoulda::Matchers::ActiveModel

Public Instance Methods

allow_mass_assignment_of(value) click to toggle source

The `allow_mass_assignment_of` matcher tests usage of Rails 3's `attr_accessible` and `attr_protected` macros, asserting that an attribute in your model is contained in either the whitelist or blacklist and thus can or cannot be set via mass assignment.

class Post
  include ActiveModel::Model

  attr_accessible :title
end

class User
  include ActiveModel::Model

  attr_protected :encrypted_password
end

# RSpec
describe Post do
  it { should allow_mass_assignment_of(:title) }
end

describe User do
  it { should_not allow_mass_assignment_of(:encrypted_password) }
end

# Test::Unit
class PostTest < ActiveSupport::TestCase
  should allow_mass_assignment_of(:title)
end

class UserTest < ActiveSupport::TestCase
  should_not allow_mass_assignment_of(:encrypted_password)
end

#### Qualifiers

##### as

Use `as` if your mass-assignment rules apply only under a certain role (Rails >= 3.1 only).

class Post
  include ActiveModel::Model

  attr_accessible :title, as: :admin
end

# RSpec
describe Post do
  it { should allow_mass_assignment_of(:title).as(:admin) }
end

# Test::Unit
class PostTest < ActiveSupport::TestCase
  should allow_mass_assignment_of(:title).as(:admin)
end

@return [AllowMassAssignmentOfMatcher]

# File lib/shoulda/matchers/active_model/allow_mass_assignment_of_matcher.rb, line 64
def allow_mass_assignment_of(value)
  AllowMassAssignmentOfMatcher.new(value)
end
allow_value(*values) click to toggle source

The `allow_value` matcher is used to test that an attribute of a model can or cannot be set to a particular value or values. It is most commonly used in conjunction with the `validates_format_of` validation.

#### should

In the positive form, `allow_value` asserts that an attribute can be set to one or more values, succeeding if none of the values cause the record to be invalid:

class UserProfile
  include ActiveModel::Model

  validates_format_of :website_url, with: URI.regexp
end

# RSpec
describe UserProfile do
  it { should allow_value('http://foo.com', 'http://bar.com/baz').for(:website_url) }
end

# Test::Unit
class UserProfileTest < ActiveSupport::TestCase
  should allow_value('http://foo.com', 'http://bar.com/baz').for(:website_url)
end

#### should_not

In the negative form, `allow_value` asserts that an attribute cannot be set to one or more values, succeeding if the first value causes the record to be invalid.

**This can be surprising** so in this case if you need to check that all of the values are invalid, use separate assertions:

class UserProfile
  include ActiveModel::Model

  validates_format_of :website_url, with: URI.regexp
end

describe UserProfile do
  # One assertion: 'buz' and 'bar' will not be tested
  it { should_not allow_value('fiz', 'buz', 'bar').for(:website_url) }

  # Three assertions, all tested separately
  it { should_not allow_value('fiz').for(:website_url) }
  it { should_not allow_value('buz').for(:website_url) }
  it { should_not allow_value('bar').for(:website_url) }
end

#### Qualifiers

##### on

Use `on` if your validation applies only under a certain context.

class UserProfile
  include ActiveModel::Model

  validates_format_of :birthday_as_string,
    with: /^(\d+)-(\d+)-(\d+)$/,
    on: :create
end

# RSpec
describe UserProfile do
  it do
    should allow_value('2013-01-01').
      for(:birthday_as_string).
      on(:create)
  end
end

# Test::Unit
class UserProfileTest < ActiveSupport::TestCase
  should allow_value('2013-01-01').
    for(:birthday_as_string).
    on(:create)
end

##### with_message

Use `with_message` if you are using a custom validation message.

class UserProfile
  include ActiveModel::Model

  validates_format_of :state,
    with: /^(open|closed)$/,
    message: 'State must be open or closed'
end

# RSpec
describe UserProfile do
  it do
    should allow_value('open', 'closed').
      for(:state).
      with_message('State must be open or closed')
  end
end

# Test::Unit
class UserProfileTest < ActiveSupport::TestCase
  should allow_value('open', 'closed').
    for(:state).
    with_message('State must be open or closed')
end

Use `with_message` with the `:against` option if the attribute the validation message is stored under is different from the attribute being validated.

class UserProfile
  include ActiveModel::Model

  validate :sports_team_must_be_valid

  private

  def sports_team_must_be_valid
    if sports_team !~ /^(Broncos|Titans)$/i
      self.errors.add :chosen_sports_team, 'Must be either a Broncos fan or a Titans fan'
    end
  end
end

# RSpec
describe UserProfile do
  it do
    should allow_value('Broncos', 'Titans').
      for(:sports_team).
      with_message('Must be either a Broncos or Titans fan',
        against: :chosen_sports_team
      )
  end
end

# Test::Unit
class UserProfileTest < ActiveSupport::TestCase
  should allow_value('Broncos', 'Titans').
    for(:sports_team).
    with_message('Must be either a Broncos or Titans fan',
      against: :chosen_sports_team
    )
end

@return [AllowValueMatcher]

# File lib/shoulda/matchers/active_model/allow_value_matcher.rb, line 153
def allow_value(*values)
  if values.empty?
    raise ArgumentError, 'need at least one argument'
  else
    AllowValueMatcher.new(*values)
  end
end
ensure_exclusion_of(attr) click to toggle source

The `ensure_exclusion_of` matcher tests usage of the `validates_exclusion_of` validation, asserting that an attribute cannot take a blacklist of values, and inversely, can take values outside of this list.

#### Qualifiers

`in_array` or `in_range` are used to test usage of the `:in` option, and so one must be used.

##### in_array

Use `in_array` if your blacklist is an array of values.

class Game
  include ActiveModel::Model

  validates_exclusion_of :supported_os, in: ['Mac', 'Linux']
end

# RSpec
describe Game do
  it { should ensure_exclusion_of(:supported_os).in_array(['Mac', 'Linux']) }
end

# Test::Unit
class GameTest < ActiveSupport::TestCase
  should ensure_exclusion_of(:supported_os).in_array(['Mac', 'Linux'])
end

##### in_range

Use `in_range` if your blacklist is a range of values.

class Game
  include ActiveModel::Model

  validates_exclusion_of :supported_os, in: ['Mac', 'Linux']
end

# RSpec
describe Game do
  it { should ensure_exclusion_of(:floors_with_enemies).in_range(5..8) }
end

# Test::Unit
class GameTest < ActiveSupport::TestCase
  should ensure_exclusion_of(:floors_with_enemies).in_range(5..8)
end

##### with_message

Use `with_message` if you are using a custom validation message.

class Game
  validates_exclusion_of :weapon,
    in: ['pistol', 'paintball gun', 'stick'],
    message: 'You chose a puny weapon'
end

# RSpec
describe Game do
  it do
    should ensure_exclusion_of(:weapon).
      in_array(['pistol', 'paintball gun', 'stick']).
      with_message('You chose a puny weapon')
  end
end

# Test::Unit
class GameTest < ActiveSupport::TestCase
  should ensure_exclusion_of(:weapon).
    in_array(['pistol', 'paintball gun', 'stick']).
    with_message('You chose a puny weapon')
end

@return [EnsureExclusionOfMatcher]

# File lib/shoulda/matchers/active_model/ensure_exclusion_of_matcher.rb, line 82
def ensure_exclusion_of(attr)
  EnsureExclusionOfMatcher.new(attr)
end
ensure_inclusion_of(attr) click to toggle source

The `ensure_inclusion_of` matcher tests usage of the `validates_inclusion_of` validation, asserting that an attribute can take a whitelist of values and cannot take values outside of this list.

#### Qualifiers

`in_array` or `in_range` are used to test usage of the `:in` option, and so one must be used.

##### in_array

Use `in_array` if your whitelist is an array of values.

class Issue
  include ActiveModel::Model

  validates_inclusion_of :state, in: %w(open resolved unresolved)
end

# RSpec
describe Issue do
  it { should ensure_inclusion_of(:state).in_array(%w(open resolved unresolved)) }
end

# Test::Unit
class IssueTest < ActiveSupport::TestCase
  should ensure_inclusion_of(:state).in_array(%w(open resolved unresolved))
end

##### in_range

Use `in_range` if your whitelist is a range of values.

class Issue
  include ActiveModel::Model

  validates_inclusion_of :priority, in: 1..5
end

# RSpec
describe Issue do
  it { should ensure_inclusion_of(:state).in_range(1..5) }
end

# Test::Unit
class IssueTest < ActiveSupport::TestCase
  should ensure_inclusion_of(:state).in_range(1..5)
end

##### with_message

Use `with_message` if you are using a custom validation message.

class Issue
  include ActiveModel::Model

  validates_inclusion_of :severity,
    in: %w(low medium high),
    message: 'Severity must be low, medium, or high'
end

# RSpec
describe Issue do
  it do
    should ensure_inclusion_of(:severity).
      in_array(%w(low medium high)).
      with_message('Severity must be low, medium, or high')
  end
end

# Test::Unit
class IssueTest < ActiveSupport::TestCase
  should ensure_inclusion_of(:severity).
    in_array(%w(low medium high)).
    with_message('Severity must be low, medium, or high')
end

##### with_low_message

Use `with_low_message` if you have a custom validation message for when a given value is too low.

class Person
  include ActiveModel::Model

  validate :age_must_be_valid

  private

  def age_must_be_valid
    if age < 65
      self.errors.add :age, 'You do not receive any benefits'
    end
  end
end

# RSpec
describe Person do
  it do
    should ensure_inclusion_of(:age).
      in_range(0..65).
      with_low_message('You do not receive any benefits')
  end
end

# Test::Unit
class PersonTest < ActiveSupport::TestCase
  should ensure_inclusion_of(:age).
    in_range(0..65).
    with_low_message('You do not receive any benefits')
end

##### with_high_message

Use `with_high_message` if you have a custom validation message for when a given value is too high.

class Person
  include ActiveModel::Model

  validate :age_must_be_valid

  private

  def age_must_be_valid
    if age > 21
      self.errors.add :age, "You're too old for this stuff"
    end
  end
end

# RSpec
describe Person do
  it do
    should ensure_inclusion_of(:age).
      in_range(0..21).
      with_high_message("You're too old for this stuff")
  end
end

# Test::Unit
class PersonTest < ActiveSupport::TestCase
  should ensure_inclusion_of(:age).
    in_range(0..21).
    with_high_message("You're too old for this stuff")
end

##### allow_nil

Use `allow_nil` to assert that the attribute allows nil.

class Issue
  include ActiveModel::Model

  validates_presence_of :state
  validates_inclusion_of :state,
    in: %w(open resolved unresolved),
    allow_nil: true
end

# RSpec
describe Issue do
  it do
    should ensure_inclusion_of(:state).
      in_array(%w(open resolved unresolved)).
      allow_nil
  end
end

# Test::Unit
class IssueTest < ActiveSupport::TestCase
  should ensure_inclusion_of(:state).
    in_array(%w(open resolved unresolved)).
    allow_nil
end

##### allow_blank

Use `allow_blank` to assert that the attribute allows blank.

class Issue
  include ActiveModel::Model

  validates_presence_of :state
  validates_inclusion_of :state,
    in: %w(open resolved unresolved),
    allow_blank: true
end

# RSpec
describe Issue do
  it do
    should ensure_inclusion_of(:state).
      in_array(%w(open resolved unresolved)).
      allow_blank
  end
end

# Test::Unit
class IssueTest < ActiveSupport::TestCase
  should ensure_inclusion_of(:state).
    in_array(%w(open resolved unresolved)).
    allow_blank
end

@return [EnsureInclusionOfMatcher]

# File lib/shoulda/matchers/active_model/ensure_inclusion_of_matcher.rb, line 211
def ensure_inclusion_of(attr)
  EnsureInclusionOfMatcher.new(attr)
end
ensure_length_of(attr) click to toggle source

The `ensure_length_of` matcher tests usage of the `validates_length_of` matcher. Note that this matcher is intended to be used against string columns and not integer columns.

#### Qualifiers

One of `is_equal_to`, `is_at_least`, or `is_at_most` must be used.

##### is_at_least

Use `is_at_least` to test usage of the `:minimum` option. This asserts that the attribute can take a string which is equal to or longer than the given length and cannot take a string which is shorter.

class User
  include ActiveModel::Model

  validates_length_of :bio, minimum: 15
end

# RSpec

describe User do
  it { should ensure_length_of(:bio).is_at_least(15) }
end

# Test::Unit

class UserTest < ActiveSupport::TestCase
  should ensure_length_of(:bio).is_at_least(15)
end

##### is_at_most

Use `is_at_most` to test usage of the `:maximum` option. This asserts that the attribute can take a string which is equal to or shorter than the given length and cannot take a string which is longer.

class User
  include ActiveModel::Model

  validates_length_of :status_update, maximum: 140
end

# RSpec
describe User do
  it { should ensure_length_of(:status_update).is_at_most(140) }
end

# Test::Unit
class UserTest < ActiveSupport::TestCase
  should ensure_length_of(:status_update).is_at_most(140)
end

##### is_equal_to

Use `is_at_equal` to test usage of the `:is` option. This asserts that the attribute can take a string which is exactly equal to the given length and cannot take a string which is shorter or longer.

class User
  include ActiveModel::Model

  validates_length_of :favorite_superhero, is: 6
end

# RSpec
describe User do
  it { should ensure_length_of(:favorite_superhero).is_equal_to(6) }
end

# Test::Unit
class UserTest < ActiveSupport::TestCase
  should ensure_length_of(:favorite_superhero).is_equal_to(6)
end

##### is_at_least + is_at_most

Use `is_at_least` and `is_at_most` to test usage of the `:in` option.

class User
  include ActiveModel::Model

  validates_length_of :password, in: 5..30
end

# RSpec
describe User do
  it { should ensure_length_of(:password).is_at_least(5).is_at_most(30) }
end

# Test::Unit
class UserTest < ActiveSupport::TestCase
  should ensure_length_of(:password).is_at_least(5).is_at_most(30)
end

##### with_message

Use `with_message` if you are using a custom validation message.

class User
  include ActiveModel::Model

  validates_length_of :api_token,
    minimum: 10,
    message: "Password isn't long enough"
end

# RSpec
describe User do
  it do
    should ensure_length_of(:password).
      is_at_least(10).
      with_message("Password isn't long enough")
  end
end

# Test::Unit
class UserTest < ActiveSupport::TestCase
  should ensure_length_of(:password).
    is_at_least(10).
    with_message("Password isn't long enough")
end

##### with_short_message

Use `with_short_message` if you are using a custom “too short” message.

class User
  include ActiveModel::Model

  validates_length_of :secret_key,
    in: 15..100,
    too_short: 'Secret key must be more than 15 characters'
end

# RSpec
describe User do
  it do
    should ensure_length_of(:secret_key).
      is_at_least(15).
      with_short_message('Secret key must be more than 15 characters')
  end
end

# Test::Unit
class UserTest < ActiveSupport::TestCase
  should ensure_length_of(:secret_key).
    is_at_least(15).
    with_short_message('Secret key must be more than 15 characters')
end

##### with_long_message

Use `with_long_message` if you are using a custom “too long” message.

class User
  include ActiveModel::Model

  validates_length_of :secret_key,
    in: 15..100,
    too_long: 'Secret key must be less than 100 characters'
end

# RSpec
describe User do
  it do
    should ensure_length_of(:secret_key).
      is_at_most(100).
      with_long_message('Secret key must be less than 100 characters')
  end
end

# Test::Unit
class UserTest < ActiveSupport::TestCase
  should ensure_length_of(:secret_key).
    is_at_most(100).
    with_long_message('Secret key must be less than 100 characters')
end

@return [EnsureLengthOfMatcher]

# File lib/shoulda/matchers/active_model/ensure_length_of_matcher.rb, line 186
def ensure_length_of(attr)
  EnsureLengthOfMatcher.new(attr)
end
have_secure_password() click to toggle source

The `have_secure_password` matcher tests usage of the `has_secure_password` macro.

#### Example

class User
  include ActiveModel::Model

  has_secure_password
end

# RSpec
describe User do
  it { should have_secure_password }
end

# Test::Unit
class UserTest < ActiveSupport::TestCase
  should have_secure_password
end

@return [HaveSecurePasswordMatcher]

# File lib/shoulda/matchers/active_model/have_secure_password_matcher.rb, line 27
def have_secure_password
  HaveSecurePasswordMatcher.new
end
validate_absence_of(attr) click to toggle source

The `validate_absence_of` matcher tests the usage of the `validates_absence_of` validation.

class Artillery
  include ActiveModel::Model

  validates_absence_of :arms
end

# RSpec
describe Artillery do
  it { should validate_absence_of(:arms) }
end

# Test::Unit
class ArtilleryTest < ActiveSupport::TestCase
  should validate_absence_of(:arms)
end

#### Qualifiers

##### with_message

Use `with_message` if you are using a custom validation message.

class Artillery
  include ActiveModel::Model

  validates_absence_of :arms, message: "We're fresh outta arms here, soldier!"
end

# RSpec
describe Artillery do
  it do
    should validate_absence_of(:arms).
      with_message("We're fresh outta arms here, soldier!")
  end
end

# Test::Unit
class ArtilleryTest < ActiveSupport::TestCase
  should validate_absence_of(:arms).
    with_message("We're fresh outta arms here, soldier!")
end

@return [ValidateAbsenceOfMatcher}

# File lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb, line 51
def validate_absence_of(attr)
  ValidateAbsenceOfMatcher.new(attr)
end
validate_acceptance_of(attr) click to toggle source

The `validate_acceptance_of` matcher tests usage of the `validates_acceptance_of` validation.

class Registration
  include ActiveModel::Model

  validates_acceptance_of :eula
end

# RSpec
describe Registration do
  it { should validate_acceptance_of(:eula) }
end

# Test::Unit
class RegistrationTest < ActiveSupport::TestCase
  should validate_acceptance_of(:eula)
end

#### Qualifiers

##### with_message

Use `with_message` if you are using a custom validation message.

class Registration
  include ActiveModel::Model

  validates_acceptance_of :terms_of_service,
    message: 'You must accept the terms of service'
end

# RSpec
describe Registration do
  it do
    should validate_acceptance_of(:terms_of_service).
      with_message('You must accept the terms of service')
  end
end

# Test::Unit
class RegistrationTest < ActiveSupport::TestCase
  should validate_acceptance_of(:terms_of_service).
    with_message('You must accept the terms of service')
end

@return [ValidateAcceptanceOfMatcher]

# File lib/shoulda/matchers/active_model/validate_acceptance_of_matcher.rb, line 52
def validate_acceptance_of(attr)
  ValidateAcceptanceOfMatcher.new(attr)
end
validate_confirmation_of(attr) click to toggle source

The `validate_confirmation_of` matcher tests usage of the `validates_confirmation_of` validation.

class User
  include ActiveModel::Model

  validates_confirmation_of :email
end

# RSpec
describe User do
  it { should validate_confirmation_of(:email) }
end

# Test::Unit
class UserTest < ActiveSupport::TestCase
  should validate_confirmation_of(:email)
end

#### Qualifiers

##### with_message

Use `with_message` if you are using a custom validation message.

class User
  include ActiveModel::Model

  validates_confirmation_of :password,
    message: 'Please re-enter your password'
end

# RSpec
describe User do
  it do
    should validate_confirmation_of(:password).
      with_message('Please re-enter your password')
  end
end

# Test::Unit
class UserTest < ActiveSupport::TestCase
  should validate_confirmation_of(:password).
    with_message('Please re-enter your password')
end

@return [ValidateConfirmationOfMatcher]

# File lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb, line 52
def validate_confirmation_of(attr)
  ValidateConfirmationOfMatcher.new(attr)
end
validate_numericality_of(attr) click to toggle source

The `validate_numericality_of` matcher tests usage of the `validates_numericality_of` validation.

class Person < ActiveRecord::Base
  validates_numericality_of :gpa
end

# RSpec
describe Person do
  it { should validate_numericality_of(:gpa) }
end

# Test::Unit
class PersonTest < ActiveSupport::TestCase
  should validate_numericality_of(:gpa)
end

#### Qualifiers

##### only_integer

Use `only_integer` to test usage of the `:only_integer` option. This asserts that your attribute only allows integer numbers and disallows non-integer ones.

class Person
  include ActiveModel::Model

  validates_numericality_of :age, only_integer: true
end

# RSpec
describe Person do
  it { should validate_numericality_of(:age).only_integer }
end

# Test::Unit
class PersonTest < ActiveSupport::TestCase
  should validate_numericality_of(:age).only_integer
end

##### is_less_than

Use `is_less_than` to test usage of the the `:less_than` option. This asserts that the attribute can take a number which is less than the given value and cannot take a number which is greater than or equal to it.

class Person
  include ActiveModel::Model

  validates_numericality_of :number_of_cars, less_than: 2
end

# RSpec
describe Person do
  it { should validate_numericality_of(:number_of_cars).is_less_than(2) }
end

# Test::Unit
class PersonTest < ActiveSupport::TestCase
  should validate_numericality_of(:number_of_cars).is_less_than(2)
end

##### is_less_than_or_equal_to

Use `is_less_than_or_equal_to` to test usage of the `:less_than_or_equal_to` option. This asserts that the attribute can take a number which is less than or equal to the given value and cannot take a number which is greater than it.

class Person
  include ActiveModel::Model

  validates_numericality_of :birth_year, less_than_or_equal_to: 1987
end

# RSpec
describe Person do
  it { should validate_numericality_of(:birth_year).is_less_than_or_equal_to(1987) }
end

# Test::Unit
class PersonTest < ActiveSupport::TestCase
  should validate_numericality_of(:birth_year).is_less_than_or_equal_to(1987)
end

##### is_equal_to

Use `is_equal_to` to test usage of the `:equal_to` option. This asserts that the attribute can take a number which is equal to the given value and cannot take a number which is not equal.

class Person
  include ActiveModel::Model

  validates_numericality_of :weight, equal_to: 150
end

# RSpec
describe Person do
  it { should validate_numericality_of(:weight).is_equal_to(150) }
end

# Test::Unit
class PersonTest < ActiveSupport::TestCase
  should validate_numericality_of(:weight).is_equal_to(150)
end

##### is_greater_than_or_equal_to

Use `is_greater_than_or_equal_to` to test usage of the `:greater_than_or_equal_to` option. This asserts that the attribute can take a number which is greater than or equal to the given value and cannot take a number which is less than it.

class Person
  include ActiveModel::Model

  validates_numericality_of :height, greater_than_or_equal_to: 55
end

# RSpec
describe Person do
  it { should validate_numericality_of(:height).is_greater_than_or_equal_to(55) }
end

# Test::Unit
class PersonTest < ActiveSupport::TestCase
  should validate_numericality_of(:height).is_greater_than_or_equal_to(55)
end

##### is_greater_than

Use `is_greater_than` to test usage of tthe `:greater_than` option. This asserts that the attribute can take a number which is greater than the given value and cannot take a number less than or equal to it.

class Person
  include ActiveModel::Model

  validates_numericality_of :legal_age, greater_than: 21
end

# RSpec
describe Person do
  it { should validate_numericality_of(:legal_age).is_greater_than(21) }
end

# Test::Unit
class PersonTest < ActiveSupport::TestCase
  should validate_numericality_of(:legal_age).is_greater_than(21)
end

##### even

Use `even` to test usage of the `:even` option. This asserts that the attribute can take odd numbers and cannot take even ones.

class Person
  include ActiveModel::Model

  validates_numericality_of :birth_month, even: true
end

# RSpec
describe Person do
  it { should validate_numericality_of(:birth_month).even }
end

# Test::Unit
class PersonTest < ActiveSupport::TestCase
  should validate_numericality_of(:birth_month).even
end

##### odd

Use `odd` to test usage of the `:odd` option. This asserts that the attribute can take a number which is odd and cannot take a number which is even.

class Person
  include ActiveModel::Model

  validates_numericality_of :birth_day, odd: true
end

# RSpec
describe Person do
  it { should validate_numericality_of(:birth_day).odd }
end

# Test::Unit
class PersonTest < ActiveSupport::TestCase
  should validate_numericality_of(:birth_day).odd
end

##### allow_nil

Use `allow_nil` to assert that the attribute allows nil.

class Person
  include ActiveModel::Model

  validate_numericality_of :rank, allow_nil: true
end

# RSpec
describe Person do
  it { should validate_numericality_of(:rank).allow_nil }
end

# Test::Unit
class PersonTest < ActiveSupport::TestCase
  should validate_uniqueness_of(:rank).allow_nil
end

##### with_message

Use `with_message` if you are using a custom validation message.

class Person
  include ActiveModel::Model

  validates_numericality_of :number_of_dependents,
    message: 'Number of dependents must be a number'
end

# RSpec
describe Person do
  it do
    should validate_numericality_of(:number_of_dependents).
      with_message('Number of dependents must be a number')
  end
end

# Test::Unit
class PersonTest < ActiveSupport::TestCase
  should validate_numericality_of(:number_of_dependents).
    with_message('Number of dependents must be a number')
end

@return [ValidateNumericalityOfMatcher]

# File lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb, line 248
def validate_numericality_of(attr)
  ValidateNumericalityOfMatcher.new(attr)
end
validate_presence_of(attr) click to toggle source

The `validate_presence_of` matcher tests usage of the `validates_presence_of` validation.

class Robot < ActiveRecord::Base
  validates_presence_of :arms
end

# RSpec
describe Robot do
  it { should validate_presence_of(:arms) }
end

# Test::Unit
class RobotTest < ActiveSupport::TestCase
  should validate_presence_of(:arms)
end

#### Qualifiers

##### with_message

Use `with_message` if you are using a custom validation message.

class Robot < ActiveRecord::Base
  validates_presence_of :legs, message: 'Robot has no legs'
end

# RSpec
describe Robot do
  it { should validate_presence_of(:legs).with_message('Robot has no legs') }
end

# Test::Unit
class RobotTest < ActiveSupport::TestCase
  should validate_presence_of(:legs).with_message('Robot has no legs')
end

@return [ValidatePresenceOfMatcher]

# File lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb, line 43
def validate_presence_of(attr)
  ValidatePresenceOfMatcher.new(attr)
end
validate_uniqueness_of(attr) click to toggle source

The `validate_uniqueness_of` matcher tests usage of the `validates_uniqueness_of` validation. It first checks for an existing instance of your model in the database, creating one if necessary. It then takes a new record and asserts that it fails validation if the attribute or attributes you've specified in the validation are set to values which are the same as those of the pre-existing record (thereby failing the uniqueness check).

class Post < ActiveRecord::Base
  validates_uniqueness_of :permalink
end

# RSpec
describe Post do
  it { should validate_uniqueness_of(:permalink) }
end

# Test::Unit
class PostTest < ActiveSupport::TestCase
  should validate_uniqueness_of(:permalink)
end

#### Caveat

This matcher works a bit differently than other matchers. As noted before, it will create an instance of your model if one doesn't already exist. Sometimes this step fails, especially if you have database-level restrictions on any attributes other than the one which is unique. In this case, the solution is to **create a record manually** before you call `validate_uniqueness_of`.

For example, say you have the following migration and model:

class CreatePosts < ActiveRecord::Migration
  def change
    create_table :posts do |t|
      t.string :title
      t.text :content, null: false
    end
  end
end

class Post < ActiveRecord::Base
  validates :title, uniqueness: true
end

You may be tempted to test the model like this:

describe Post do
  it { should validate_uniqueness_of(:title) }
end

However, running this test will fail with something like:

Failures:

  1) Post should require case sensitive unique value for title
     Failure/Error: it { should validate_uniqueness_of(:title) }
     ActiveRecord::StatementInvalid:
       SQLite3::ConstraintException: posts.content may not be NULL: INSERT INTO "posts" ("title") VALUES (?)

To fix this, you'll need to write this instead:

describe Post do
  it do
    Post.create!(content: 'Here is the content')
    should validate_uniqueness_of(:title)
  end
end

Or, if you're using [FactoryGirl](github.com/thoughtbot/factory_girl) and you have a `post` factory defined which automatically sets `content`, you can say:

describe Post do
  it do
    FactoryGirl.create(:post)
    should validate_uniqueness_of(:title)
  end
end

#### Qualifiers

##### with_message

Use `with_message` if you are using a custom validation message.

class Post < ActiveRecord::Base
  validates_uniqueness_of :title, message: 'Please choose another title'
end

# RSpec
describe Post do
  it do
    should validate_uniqueness_of(:title).
      with_message('Please choose another title')
  end
end

# Test::Unit
class PostTest < ActiveSupport::TestCase
  should validate_uniqueness_of(:title).
    with_message('Please choose another title')
end

##### scoped_to

Use `scoped_to` to test usage of the `:scope` option. This asserts that a new record fails validation if not only the primary attribute is not unique, but the scoped attributes are not unique either.

class Post < ActiveRecord::Base
  validates_uniqueness_of :slug, scope: :user_id
end

# RSpec
describe Post do
  it { should validate_uniqueness_of(:slug).scoped_to(:journal_id) }
end

# Test::Unit
class PostTest < ActiveSupport::TestCase
  should validate_uniqueness_of(:slug).scoped_to(:journal_id)
end

##### case_insensitive

Use `case_insensitive` to test usage of the `:case_sensitive` option with a false value. This asserts that the uniquable attributes fail validation even if their values are a different case than corresponding attributes in the pre-existing record.

class Post < ActiveRecord::Base
  validates_uniqueness_of :key, case_sensitive: false
end

# RSpec
describe Post do
  it { should validate_uniqueness_of(:key).case_insensitive }
end

# Test::Unit
class PostTest < ActiveSupport::TestCase
  should validate_uniqueness_of(:key).case_insensitive
end

##### allow_nil

Use `allow_nil` to assert that the attribute allows nil.

class Post < ActiveRecord::Base
  validates_uniqueness_of :author_id, allow_nil: true
end

# RSpec
describe Post do
  it { should validate_uniqueness_of(:author_id).allow_nil }
end

# Test::Unit
class PostTest < ActiveSupport::TestCase
  should validate_uniqueness_of(:author_id).allow_nil
end

@return [ValidateUniquenessOfMatcher]

# File lib/shoulda/matchers/active_model/validate_uniqueness_of_matcher.rb, line 170
def validate_uniqueness_of(attr)
  ValidateUniquenessOfMatcher.new(attr)
end