Module: Shoulda::ActiveRecord::Matchers

Matchers for your active record models

These matchers will test most of the validations and associations for your ActiveRecord models.

  describe User do
    it { should validate_presence_of(:name) }
    it { should validate_presence_of(:phone_number) }
    %w(abcd 1234).each do |value|
      it { should_not allow_value(value).for(:phone_number) }
    end
    it { should allow_value("(123) 456-7890").for(:phone_number) }
    it { should_not allow_mass_assignment_of(:password) }
    it { should have_one(:profile) }
    it { should have_many(:dogs) }
    it { should have_many(:messes).through(:dogs) }
    it { should belong_to(:lover) }
  end

Public Visibility

Public Instance Method Summary

#allow_mass_assignment_of(value)

Ensures that the attribute can be set on mass update.

#allow_value(value)

Ensures that the attribute can be set to the given value.

#belong_to(name)

Ensure that the belongs_to relationship exists.

#ensure_inclusion_of(attr)

Ensure that the attribute’s value is in the range specified.

#ensure_length_of(attr)

Ensures that the length of the attribute is validated.

#have_and_belong_to_many(name)

Ensures that the has_and_belongs_to_many relationship exists, and that the join table is in place.

#have_db_column(column)

Ensures the database column exists.

#have_index(columns)

Ensures that there are DB indices on the given columns or tuples of columns.

#have_many(name)

Ensures that the has_many relationship exists.

#have_named_scope(scope_call)

Ensures that the model has a method named scope_call that returns a NamedScope object with the proxy options set to the options you supply.

#have_one(name)

Ensure that the has_one relationship exists.

#have_readonly_attribute(value)

Ensures that the attribute cannot be changed once the record has been created.

#validate_acceptance_of(attr)

Ensures that the model cannot be saved the given attribute is not accepted.

#validate_numericality_of(attr)

Ensure that the attribute is numeric.

#validate_presence_of(attr)

Ensures that the model is not valid if the given attribute is not present.

#validate_uniqueness_of(attr)

Ensures that the model is invalid if the given attribute is not unique.

Public Instance Method Details

allow_mass_assignment_of

public allow_mass_assignment_of(value)

Ensures that the attribute can be set on mass update.

  it { should_not allow_mass_assignment_of(:password) }
  it { should allow_mass_assignment_of(:first_name) }
[View source]


10
11
12
# File 'lib/shoulda/active_record/matchers/allow_mass_assignment_of_matcher.rb', line 10

def allow_mass_assignment_of(value)
  AllowMassAssignmentOfMatcher.new(value)
end

allow_value

public allow_value(value)

Ensures that the attribute can be set to the given value.

Options:

  • with_message - value the test expects to find in errors.on(:attribute). Regexp or string. Defaults to the translation for :invalid.

Example:

  it { should_not allow_value('bad').for(:isbn) }
  it { should allow_value("isbn 1 2345 6789 0").for(:isbn) }
[View source]


16
17
18
# File 'lib/shoulda/active_record/matchers/allow_value_matcher.rb', line 16

def allow_value(value)
  AllowValueMatcher.new(value)
end

belong_to

public belong_to(name)

Ensure that the belongs_to relationship exists.

  it { should belong_to(:parent) }
[View source]


9
10
11
# File 'lib/shoulda/active_record/matchers/association_matcher.rb', line 9

def belong_to(name)
  AssociationMatcher.new(:belongs_to, name)
end

ensure_inclusion_of

public ensure_inclusion_of(attr)

Ensure that the attribute’s value is in the range specified

Options:

  • in_range - the range of allowed values for this attribute
  • with_low_message - value the test expects to find in errors.on(:attribute). Regexp or string. Defaults to the translation for :inclusion.
  • with_high_message - value the test expects to find in errors.on(:attribute). Regexp or string. Defaults to the translation for :inclusion.

Example:

  it { should ensure_inclusion_of(:age).in_range(0..100) }
[View source]


19
20
21
# File 'lib/shoulda/active_record/matchers/ensure_inclusion_of_matcher.rb', line 19

def ensure_inclusion_of(attr)
  EnsureInclusionOfMatcher.new(attr)
end

ensure_length_of

public ensure_length_of(attr)

Ensures that the length of the attribute is validated.

Options:

  • is_at_least - minimum length of this attribute
  • is_at_most - maximum length of this attribute
  • is_equal_to - exact requred length of this attribute
  • with_short_message - value the test expects to find in errors.on(:attribute). Regexp or string. Defaults to the translation for :too_short.
  • with_long_message - value the test expects to find in errors.on(:attribute). Regexp or string. Defaults to the translation for :too_long.
  • with_message - value the test expects to find in errors.on(:attribute). Regexp or string. Defaults to the translation for :wrong_length. Used in conjunction with is_equal_to.

Examples:

  it { should ensure_length_of(:password).
                is_at_least(6).
                is_at_most(20) }
  it { should ensure_length_of(:name).
                is_at_least(3).
                with_short_message(/not long enough/) }
  it { should ensure_length_of(:ssn).
                is_equal_to(9).
                with_message(/is invalid/) }
[View source]


32
33
34
# File 'lib/shoulda/active_record/matchers/ensure_length_of_matcher.rb', line 32

def ensure_length_of(attr)
  EnsureLengthOfMatcher.new(attr)
end

have_and_belong_to_many

public have_and_belong_to_many(name)

Ensures that the has_and_belongs_to_many relationship exists, and that the join table is in place.

  it { should have_and_belong_to_many(:posts) }
[View source]


51
52
53
# File 'lib/shoulda/active_record/matchers/association_matcher.rb', line 51

def have_and_belong_to_many(name)
  AssociationMatcher.new(:has_and_belongs_to_many, name)
end

have_db_column

public have_db_column(column)

Ensures the database column exists.

Options:

  • of_type - db column type (:integer, :string, etc.)
  • with_options - same options available in migrations (:default, :null, :limit, :precision, :scale)

Examples:

  it { should_not have_db_column(:admin).of_type(:boolean) }
  it { should have_db_column(:salary).
                of_type(:decimal).
                with_options(:precision => 10, :scale => 2) }
[View source]


18
19
20
# File 'lib/shoulda/active_record/matchers/have_db_column_matcher.rb', line 18

def have_db_column(column)
  HaveDbColumnMatcher.new(:have_db_column, column)
end

have_index

public have_index(columns)

Ensures that there are DB indices on the given columns or tuples of columns.

Options:

  • unique - whether or not the index has a unique constraint. Use true to explicitly test for a unique constraint. Use false to explicitly test for a non-unique constraint. Use nil if you don’t care whether the index is unique or not. Default = nil

Examples:

  it { should have_index(:age) }
  it { should have_index([:commentable_type, :commentable_id]) }
  it { should have_index(:ssn).unique(true) }
[View source]


21
22
23
# File 'lib/shoulda/active_record/matchers/have_index_matcher.rb', line 21

def have_index(columns)
  HaveIndexMatcher.new(:have_index, columns)
end

have_many

public have_many(name)

Ensures that the has_many relationship exists. Will also test that the associated table has the required columns. Works with polymorphic associations.

Options:

  • through - association name for has_many :through
  • dependent - tests that the association makes use of the dependent option.

Example:

  it { should_have_many(:friends) }
  it { should_have_many(:enemies).through(:friends) }
  it { should_have_many(:enemies).dependent(:destroy) }
[View source]


27
28
29
# File 'lib/shoulda/active_record/matchers/association_matcher.rb', line 27

def have_many(name)
  AssociationMatcher.new(:has_many, name)
end

have_named_scope

public have_named_scope(scope_call)

Ensures that the model has a method named scope_call that returns a NamedScope object with the proxy options set to the options you supply. scope_call can be either a symbol, or a Ruby expression in a String which will be evaled. The eval’d method call has access to all the same instance variables that an example would.

Options:

 * <tt>in_context</tt> - Any of the options that the named scope would
   pass on to find.

Example:

  it { should have_named_scope(:visible).
                finding(:conditions => {:visible => true}) }

Passes for

  named_scope :visible, :conditions => {:visible => true}

Or for

  def self.visible
    scoped(:conditions => {:visible => true})
  end

You can test lambdas or methods that return ActiveRecord#scoped calls:

  it { should have_named_scope('recent(5)').finding(:limit => 5) }
  it { should have_named_scope('recent(1)').finding(:limit => 1) }

Passes for

  named_scope :recent, lambda {|c| {:limit => c}}

Or for

  def self.recent(c)
    scoped(:limit => c)
  end
[View source]


45
46
47
# File 'lib/shoulda/active_record/matchers/have_named_scope_matcher.rb', line 45

def have_named_scope(scope_call)
  HaveNamedScopeMatcher.new(scope_call).in_context(self)
end

have_one

public have_one(name)

Ensure that the has_one relationship exists. Will also test that the associated table has the required columns. Works with polymorphic associations.

Options:

  • :dependent - tests that the association makes use of the dependent option.

Example:

  it { should have_one(:god) } # unless hindu
[View source]


42
43
44
# File 'lib/shoulda/active_record/matchers/association_matcher.rb', line 42

def have_one(name)
  AssociationMatcher.new(:has_one, name)
end

have_readonly_attribute

public have_readonly_attribute(value)

Ensures that the attribute cannot be changed once the record has been created.

  it { should have_readonly_attributes(:password) }
[View source]


10
11
12
# File 'lib/shoulda/active_record/matchers/have_readonly_attribute_matcher.rb', line 10

def have_readonly_attribute(value)
  HaveReadonlyAttributeMatcher.new(value)
end

validate_acceptance_of

public validate_acceptance_of(attr)

Ensures that the model cannot be saved the given attribute is not accepted.

Options:

  • with_message - value the test expects to find in errors.on(:attribute). Regexp or string. Defaults to the translation for :accepted.

Example:

  it { should validate_acceptance_of(:eula) }
[View source]


16
17
18
# File 'lib/shoulda/active_record/matchers/validate_acceptance_of_matcher.rb', line 16

def validate_acceptance_of(attr)
  ValidateAcceptanceOfMatcher.new(attr)
end

validate_numericality_of

public validate_numericality_of(attr)

Ensure that the attribute is numeric

Options:

  • with_message - value the test expects to find in errors.on(:attribute). Regexp or string. Defaults to the translation for :not_a_number.

Example:

  it { should validate_numericality_of(:age) }
[View source]


15
16
17
# File 'lib/shoulda/active_record/matchers/validate_numericality_of_matcher.rb', line 15

def validate_numericality_of(attr)
  ValidateNumericalityOfMatcher.new(attr)
end

validate_presence_of

public validate_presence_of(attr)

Ensures that the model is not valid if the given attribute is not present.

Options:

  • with_message - value the test expects to find in errors.on(:attribute). Regexp or String. Defaults to the translation for :blank.

Examples:

  it { should validate_presence_of(:name) }
  it { should validate_presence_of(:name).
                with_message(/is not optional/) }
[View source]


18
19
20
# File 'lib/shoulda/active_record/matchers/validate_presence_of_matcher.rb', line 18

def validate_presence_of(attr)
  ValidatePresenceOfMatcher.new(attr)
end

validate_uniqueness_of

public validate_uniqueness_of(attr)

Ensures that the model is invalid if the given attribute is not unique.

Internally, this uses values from existing records to test validations, so this will always fail if you have not saved at least one record for the model being tested, like so:

  describe User do
    before(:each) { User.create!(:email => 'address@example.com') }
    it { should validate_uniqueness_of(:email) }
  end

Options:

  • with_message - value the test expects to find in errors.on(:attribute). Regexp or String. Defaults to the translation for :taken.
  • scoped_to - field(s) to scope the uniqueness to.
  • case_insensitive - ensures that the validation does not check case. Off by default. Ignored by non-text attributes.

Examples:

  it { should validate_uniqueness_of(:keyword) }
  it { should validate_uniqueness_of(:keyword).with_message(/dup/) }
  it { should validate_uniqueness_of(:email).scoped_to(:name) }
  it { should validate_uniqueness_of(:email).
                scoped_to(:first_name, :last_name) }
  it { should validate_uniqueness_of(:keyword).case_insensitive }
[View source]


33
34
35
# File 'lib/shoulda/active_record/matchers/validate_uniqueness_of_matcher.rb', line 33

def validate_uniqueness_of(attr)
  ValidateUniquenessOfMatcher.new(attr)
end