Module: Shoulda::Matchers::ActiveRecord

Defined in:
lib/shoulda/matchers/active_record.rb,
lib/shoulda/matchers/active_record/serialize_matcher.rb,
lib/shoulda/matchers/active_record/association_matcher.rb,
lib/shoulda/matchers/active_record/association_matchers.rb,
lib/shoulda/matchers/active_record/have_db_index_matcher.rb,
lib/shoulda/matchers/active_record/have_db_column_matcher.rb,
lib/shoulda/matchers/active_record/define_enum_for_matcher.rb,
lib/shoulda/matchers/active_record/have_readonly_attribute_matcher.rb,
lib/shoulda/matchers/active_record/association_matchers/order_matcher.rb,
lib/shoulda/matchers/active_record/association_matchers/source_matcher.rb,
lib/shoulda/matchers/active_record/association_matchers/option_verifier.rb,
lib/shoulda/matchers/active_record/association_matchers/through_matcher.rb,
lib/shoulda/matchers/active_record/accept_nested_attributes_for_matcher.rb,
lib/shoulda/matchers/active_record/association_matchers/model_reflector.rb,
lib/shoulda/matchers/active_record/association_matchers/model_reflection.rb,
lib/shoulda/matchers/active_record/association_matchers/dependent_matcher.rb,
lib/shoulda/matchers/active_record/association_matchers/inverse_of_matcher.rb,
lib/shoulda/matchers/active_record/association_matchers/join_table_matcher.rb,
lib/shoulda/matchers/active_record/association_matchers/counter_cache_matcher.rb

Instance Method Summary (collapse)

Instance Method Details

- (AcceptNestedAttributesForMatcher) accept_nested_attributes_for(name)

The accept_nested_attributes_for matcher tests usage of the accepts_nested_attributes_for macro.

class Car < ActiveRecord::Base
  accepts_nested_attributes_for :doors
end

# RSpec
describe Car do
  it { should accept_nested_attributes_for(:doors) }
end

# Test::Unit (using Shoulda)
class CarTest < ActiveSupport::TestCase
  should accept_nested_attributes_for(:doors)
end

Qualifiers

allow_destroy

Use allow_destroy to assert that the :allow_destroy option was specified.

class Car < ActiveRecord::Base
  accepts_nested_attributes_for :mirrors, allow_destroy: true
end

# RSpec
describe Car do
  it do
    should accept_nested_attributes_for(:mirrors).
      allow_destroy(true)
  end
end

# Test::Unit
class CarTest < ActiveSupport::TestCase
  should accept_nested_attributes_for(:mirrors).
    allow_destroy(true)
end
limit

Use limit to assert that the :limit option was specified.

class Car < ActiveRecord::Base
  accepts_nested_attributes_for :windows, limit: 3
end

# RSpec
describe Car do
  it do
    should accept_nested_attributes_for(:windows).
      limit(3)
  end
end

# Test::Unit
class CarTest < ActiveSupport::TestCase
  should accept_nested_attributes_for(:windows).
    limit(3)
end
update_only

Use update_only to assert that the :update_only option was specified.

class Car < ActiveRecord::Base
  accepts_nested_attributes_for :engine, update_only: true
end

# RSpec
describe Car do
  it do
    should accept_nested_attributes_for(:engine).
      update_only(true)
  end
end

# Test::Unit
class CarTest < ActiveSupport::TestCase
  should accept_nested_attributes_for(:engine).
    update_only(true)
end


93
94
95
# File 'lib/shoulda/matchers/active_record/accept_nested_attributes_for_matcher.rb', line 93

def accept_nested_attributes_for(name)
  AcceptNestedAttributesForMatcher.new(name)
end

- (AssociationMatcher) belong_to(name)

The belong_to matcher is used to ensure that a belong_to association exists on your model.

class Person < ActiveRecord::Base
  belongs_to :organization
end

# RSpec
describe Person do
  it { should belong_to(:organization) }
end

# Test::Unit
class PersonTest < ActiveSupport::TestCase
  should belong_to(:organization)
end

Note that polymorphic associations are automatically detected and do not need any qualifiers:

class Comment < ActiveRecord::Base
  belongs_to :commentable, polymorphic: true
end

# RSpec
describe Comment do
  it { should belong_to(:commentable) }
end

# Test::Unit
class CommentTest < ActiveSupport::TestCase
  should belong_to(:commentable)
end

Qualifiers

conditions

Use conditions if your association is defined with a scope that sets the where clause.

class Person < ActiveRecord::Base
  belongs_to :family, -> { where(everyone_is_perfect: false) }
end

# RSpec
describe Person do
  it do
    should belong_to(:family).
      conditions(everyone_is_perfect: false)
  end
end

# Test::Unit
class PersonTest < ActiveSupport::TestCase
  should belong_to(:family).
    conditions(everyone_is_perfect: false)
end
order

Use order if your association is defined with a scope that sets the order clause.

class Person < ActiveRecord::Base
  belongs_to :previous_company, -> { order('hired_on desc') }
end

# RSpec
describe Person do
  it { should belong_to(:previous_company).order('hired_on desc') }
end

# Test::Unit
class PersonTest < ActiveSupport::TestCase
  should belong_to(:previous_company).order('hired_on desc')
end
class_name

Use class_name to test usage of the :class_name option. This asserts that the model you're referring to actually exists.

class Person < ActiveRecord::Base
  belongs_to :ancient_city, class_name: 'City'
end

# RSpec
describe Person do
  it { should belong_to(:ancient_city).class_name('City') }
end

# Test::Unit
class PersonTest < ActiveSupport::TestCase
  should belong_to(:ancient_city).class_name('City')
end
with_foreign_key

Use with_foreign_key to test usage of the :foreign_key option.

class Person < ActiveRecord::Base
  belongs_to :great_country, foreign_key: 'country_id'
end

# RSpec
describe Person do
  it do
    should belong_to(:great_country).
      with_foreign_key('country_id')
  end
end

# Test::Unit
class PersonTest < ActiveSupport::TestCase
  should belong_to(:great_country).
    with_foreign_key('country_id')
end
dependent

Use dependent to assert that the :dependent option was specified.

class Person < ActiveRecord::Base
  belongs_to :world, dependent: :destroy
end

# RSpec
describe Person do
  it { should belong_to(:world).dependent(:destroy) }
end

# Test::Unit
class PersonTest < ActiveSupport::TestCase
  should belong_to(:world).dependent(:destroy)
end
counter_cache

Use counter_cache to assert that the :counter_cache option was specified.

class Person < ActiveRecord::Base
  belongs_to :organization, counter_cache: true
end

# RSpec
describe Person do
  it { should belong_to(:organization).counter_cache(true) }
end

# Test::Unit
class PersonTest < ActiveSupport::TestCase
  should belong_to(:organization).counter_cache(true)
end
touch

Use touch to assert that the :touch option was specified.

class Person < ActiveRecord::Base
  belongs_to :organization, touch: true
end

# RSpec
describe Person do
  it { should belong_to(:organization).touch(true) }
end

# Test::Unit
class PersonTest < ActiveSupport::TestCase
  should belong_to(:organization).touch(true)
end

autosave

Use autosave to assert that the :autosave option was specified.

class Account < ActiveRecord::Base
  belongs_to :bank, autosave: true
end

# RSpec
describe Account do
  it { should belong_to(:bank).autosave(true) }
end

# Test::Unit
class AccountTest < ActiveSupport::TestCase
  should belong_to(:bank).autosave(true)
end
inverse_of

Use inverse_of to assert that the :inverse_of option was specified.

class Person < ActiveRecord::Base
  belongs_to :organization, inverse_of: :employees
end

# RSpec
describe Person
  it { should belong_to(:organization).inverse_of(:employees) }
end

# Test::Unit
class PersonTest < ActiveSupport::TestCase
  should belong_to(:organization).inverse_of(:employees)
end


218
219
220
# File 'lib/shoulda/matchers/active_record/association_matcher.rb', line 218

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

- (DefineEnumForMatcher) define_enum_for(attribute_name)

The define_enum_for matcher is used to test that the enum macro has been used to decorate an attribute with enum methods.

class Process < ActiveRecord::Base
  enum status: [:running, :stopped, :suspended]
end

# RSpec
describe Process do
  it { should define_enum_for(:status) }
  end
end

# Test::Unit
class ProcessTest < ActiveSupport::TestCase
  should define_enum_for(:status)
end

Qualifiers

with

Use with to test that the enum has been defined with a certain set of known values.

class Process < ActiveRecord::Base
  enum status: [:running, :stopped, :suspended]
end

# RSpec
describe Process do
  it do
    should define_enum_for(:status).
      with([:running, :stopped, :suspended])
  end
end

# Test::Unit
class ProcessTest < ActiveSupport::TestCase
  should define_enum_for(:status).
    with([:running, :stopped, :suspended])
end


49
50
51
# File 'lib/shoulda/matchers/active_record/define_enum_for_matcher.rb', line 49

def define_enum_for(attribute_name)
  DefineEnumForMatcher.new(attribute_name)
end

- (AssociationMatcher) have_and_belong_to_many(name)

The have_and_belong_to_many matcher is used to test that a has_and_belongs_to_many association exists on your model and that the join table exists in the database.

class Person < ActiveRecord::Base
  has_and_belongs_to_many :awards
end

# RSpec
describe Person do
  it { should have_and_belong_to_many(:awards) }
end

# Test::Unit
class PersonTest < ActiveSupport::TestCase
  should have_and_belong_to_many(:awards)
end

Qualifiers

conditions

Use conditions if your association is defined with a scope that sets the where clause.

class Person < ActiveRecord::Base
  has_and_belongs_to_many :issues, -> { where(difficulty: 'hard') }
end

# RSpec
describe Person do
  it do
    should have_and_belong_to_many(:issues).
      conditions(difficulty: 'hard')
  end
end

# Test::Unit
class PersonTest < ActiveSupport::TestCase
  should have_and_belong_to_many(:issues).
    conditions(difficulty: 'hard')
end
order

Use order if your association is defined with a scope that sets the order clause.

class Person < ActiveRecord::Base
  has_and_belongs_to_many :projects, -> { order('time_spent') }
end

# RSpec
describe Person do
  it do
    should have_and_belong_to_many(:projects).
      order('time_spent')
  end
end

# Test::Unit
class PersonTest < ActiveSupport::TestCase
  should have_and_belong_to_many(:projects).
    order('time_spent')
end
class_name

Use class_name to test usage of the :class_name option. This asserts that the model you're referring to actually exists.

class Person < ActiveRecord::Base
  has_and_belongs_to_many :places_visited, class_name: 'City'
end

# RSpec
describe Person do
  it do
    should have_and_belong_to_many(:places_visited).
      class_name('City')
  end
end

# Test::Unit
class PersonTest < ActiveSupport::TestCase
  should have_and_belong_to_many(:places_visited).
    class_name('City')
end
validate

Use validate to test that the :validate option was specified.

class Person < ActiveRecord::Base
  has_and_belongs_to_many :interviews, validate: false
end

# RSpec
describe Person do
  it do
    should have_and_belong_to_many(:interviews).
      validate(false)
  end
end

# Test::Unit
class PersonTest < ActiveSupport::TestCase
  should have_and_belong_to_many(:interviews).
    validate(false)
end

autosave

Use autosave to assert that the :autosave option was specified.

class Publisher < ActiveRecord::Base
  has_and_belongs_to_many :advertisers, autosave: true
end

# RSpec
describe Publisher do
  it { should have_and_belong_to_many(:advertisers).autosave(true) }
end

# Test::Unit
class AccountTest < ActiveSupport::TestCase
  should have_and_belong_to_many(:advertisers).autosave(true)
end


743
744
745
# File 'lib/shoulda/matchers/active_record/association_matcher.rb', line 743

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

- (HaveDbColumnMatcher) have_db_column(column)

The have_db_column matcher tests that the table that backs your model has a specific column.

class CreatePhones < ActiveRecord::Migration
  def change
    create_table :phones do |t|
      t.string :supported_ios_version
    end
  end
end

# RSpec
describe Phone do
  it { should have_db_column(:supported_ios_version) }
end

# Test::Unit
class PhoneTest < ActiveSupport::TestCase
  should have_db_column(:supported_ios_version)
end

Qualifiers

of_type

Use of_type to assert that a column is defined as a certain type.

class CreatePhones < ActiveRecord::Migration
  def change
    create_table :phones do |t|
      t.decimal :camera_aperture
    end
  end
end

# RSpec
describe Phone do
  it do
    should have_db_column(:camera_aperture).of_type(:decimal)
  end
end

# Test::Unit
class PhoneTest < ActiveSupport::TestCase
  should have_db_column(:camera_aperture).of_type(:decimal)
end
with_options

Use with_options to assert that a column has been defined with certain options (:precision, :limit, :default, :null, :scale, or :primary).

class CreatePhones < ActiveRecord::Migration
  def change
    create_table :phones do |t|
      t.decimal :camera_aperture, precision: 1, null: false
    end
  end
end

# RSpec
describe Phone do
  it do
    should have_db_column(:camera_aperture).
      with_options(precision: 1, null: false)
  end
end

# Test::Unit
class PhoneTest < ActiveSupport::TestCase
  should have_db_column(:camera_aperture).
    with_options(precision: 1, null: false)
end


81
82
83
# File 'lib/shoulda/matchers/active_record/have_db_column_matcher.rb', line 81

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

- (HaveDbIndexMatcher) have_db_index(columns)

The have_db_index matcher tests that the table that backs your model has a index on a specific column.

class CreateBlogs < ActiveRecord::Migration
  def change
    create_table :blogs do |t|
      t.integer :user_id
    end

    add_index :blogs, :user_id
  end
end

# RSpec
describe Blog do
  it { should have_db_index(:user_id) }
end

# Test::Unit
class BlogTest < ActiveSupport::TestCase
  should have_db_index(:user_id)
end

Qualifiers

unique

Use unique to assert that the index is unique.

class CreateBlogs < ActiveRecord::Migration
  def change
    create_table :blogs do |t|
      t.string :name
    end

    add_index :blogs, :name, unique: true
  end
end

# RSpec
describe Blog do
  it { should have_db_index(:name).unique(true) }
end

# Test::Unit
class BlogTest < ActiveSupport::TestCase
  should have_db_index(:name).unique(true)
end

Since it only ever makes since for unique to be true, you can also leave off the argument to save some keystrokes:

# RSpec
describe Blog do
  it { should have_db_index(:name).unique }
end

# Test::Unit
class BlogTest < ActiveSupport::TestCase
  should have_db_index(:name).unique
end


68
69
70
# File 'lib/shoulda/matchers/active_record/have_db_index_matcher.rb', line 68

def have_db_index(columns)
  HaveDbIndexMatcher.new(columns)
end

- (AssociationMatcher) have_many(name)

The have_many matcher is used to test that a has_many or has_many :through association exists on your model.

class Person < ActiveRecord::Base
  has_many :friends
end

# RSpec
describe Person do
  it { should have_many(:friends) }
end

# Test::Unit
class PersonTest < ActiveSupport::TestCase
  should have_many(:friends)
end

Qualifiers

conditions

Use conditions if your association is defined with a scope that sets the where clause.

class Person < ActiveRecord::Base
  has_many :coins, -> { where(quality: 'mint') }
end

# RSpec
describe Person do
  it { should have_many(:coins).conditions(quality: 'mint') }
end

# Test::Unit
class PersonTest < ActiveSupport::TestCase
  should have_many(:coins).conditions(quality: 'mint')
end
order

Use order if your association is defined with a scope that sets the order clause.

class Person < ActiveRecord::Base
  has_many :shirts, -> { order('color') }
end

# RSpec
describe Person do
  it { should have_many(:shirts).order('color') }
end

# Test::Unit
class PersonTest < ActiveSupport::TestCase
  should have_many(:shirts).order('color')
end
class_name

Use class_name to test usage of the :class_name option. This asserts that the model you're referring to actually exists.

class Person < ActiveRecord::Base
  has_many :hopes, class_name: 'Dream'
end

# RSpec
describe Person do
  it { should have_many(:hopes).class_name('Dream') }
end

# Test::Unit
class PersonTest < ActiveSupport::TestCase
  should have_many(:hopes).class_name('Dream')
end
with_foreign_key

Use with_foreign_key to test usage of the :foreign_key option.

class Person < ActiveRecord::Base
  has_many :worries, foreign_key: 'worrier_id'
end

# RSpec
describe Person do
  it { should have_many(:worries).with_foreign_key('worrier_id') }
end

# Test::Unit
class PersonTest < ActiveSupport::TestCase
  should have_many(:worries).with_foreign_key('worrier_id')
end
dependent

Use dependent to assert that the :dependent option was specified.

class Person < ActiveRecord::Base
  has_many :secret_documents, dependent: :destroy
end

# RSpec
describe Person do
  it { should have_many(:secret_documents).dependent(:destroy) }
end

# Test::Unit
class PersonTest < ActiveSupport::TestCase
  should have_many(:secret_documents).dependent(:destroy)
end
through

Use through to test usage of the :through option. This asserts that the association you are going through actually exists.

class Person < ActiveRecord::Base
  has_many :acquaintances, through: :friends
end

# RSpec
describe Person do
  it { should have_many(:acquaintances).through(:friends) }
end

# Test::Unit
class PersonTest < ActiveSupport::TestCase
  should have_many(:acquaintances).through(:friends)
end
source

Use source to test usage of the :source option on a :through association.

class Person < ActiveRecord::Base
  has_many :job_offers, through: :friends, source: :opportunities
end

# RSpec
describe Person do
  it do
    should have_many(:job_offers).
      through(:friends).
      source(:opportunities)
  end
end

# Test::Unit
class PersonTest < ActiveSupport::TestCase
  should have_many(:job_offers).
    through(:friends).
    source(:opportunities)
end
validate

Use validate to assert that the :validate option was specified.

class Person < ActiveRecord::Base
  has_many :ideas, validate: false
end

# RSpec
describe Person do
  it { should have_many(:ideas).validate(false) }
end

# Test::Unit
class PersonTest < ActiveSupport::TestCase
  should have_many(:ideas).validate(false)
end

autosave

Use autosave to assert that the :autosave option was specified.

class Player < ActiveRecord::Base
  has_many :games, autosave: true
end

# RSpec
describe Player do
  it { should have_many(:games).autosave(true) }
end

# Test::Unit
class PlayerTest < ActiveSupport::TestCase
  should have_many(:games).autosave(true)
end


416
417
418
# File 'lib/shoulda/matchers/active_record/association_matcher.rb', line 416

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

- (AssociationMatcher) have_one(name)

The have_one matcher is used to test that a has_one or has_one :through association exists on your model.

class Person < ActiveRecord::Base
  has_one :partner
end

# RSpec
describe Person do
  it { should have_one(:partner) }
end

# Test::Unit
class PersonTest < ActiveSupport::TestCase
  should have_one(:partner)
end

Qualifiers

conditions

Use conditions if your association is defined with a scope that sets the where clause.

class Person < ActiveRecord::Base
  has_one :pet, -> { where('weight < 80') }
end

# RSpec
describe Person do
  it { should have_one(:pet).conditions('weight < 80') }
end

# Test::Unit
class PersonTest < ActiveSupport::TestCase
  should have_one(:pet).conditions('weight < 80')
end
order

Use order if your association is defined with a scope that sets the order clause.

class Person < ActiveRecord::Base
  has_one :focus, -> { order('priority desc') }
end

# RSpec
describe Person do
  it { should have_one(:focus).order('priority desc') }
end

# Test::Unit
class PersonTest < ActiveSupport::TestCase
  should have_one(:focus).order('priority desc')
end
class_name

Use class_name to test usage of the :class_name option. This asserts that the model you're referring to actually exists.

class Person < ActiveRecord::Base
  has_one :chance, class_name: 'Opportunity'
end

# RSpec
describe Person do
  it { should have_one(:chance).class_name('Opportunity') }
end

# Test::Unit
class PersonTest < ActiveSupport::TestCase
  should have_one(:chance).class_name('Opportunity')
end
dependent

Use dependent to test that the :dependent option was specified.

class Person < ActiveRecord::Base
  has_one :contract, dependent: :nullify
end

# RSpec
describe Person do
  it { should have_one(:contract).dependent(:nullify) }
end

# Test::Unit
class PersonTest < ActiveSupport::TestCase
  should have_one(:contract).dependent(:nullify)
end
with_foreign_key

Use with_foreign_key to test usage of the :foreign_key option.

class Person < ActiveRecord::Base
  has_one :job, foreign_key: 'worker_id'
end

# RSpec
describe Person do
  it { should have_one(:job).with_foreign_key('worker_id') }
end

# Test::Unit
class PersonTest < ActiveSupport::TestCase
  should have_one(:job).with_foreign_key('worker_id')
end
through

Use through to test usage of the :through option. This asserts that the association you are going through actually exists.

class Person < ActiveRecord::Base
  has_one :life, through: :partner
end

# RSpec
describe Person do
  it { should have_one(:life).through(:partner) }
end

# Test::Unit
class PersonTest < ActiveSupport::TestCase
  should have_one(:life).through(:partner)
end
source

Use source to test usage of the :source option on a :through association.

class Person < ActiveRecord::Base
  has_one :car, through: :partner, source: :vehicle
end

# RSpec
describe Person do
  it { should have_one(:car).through(:partner).source(:vehicle) }
end

# Test::Unit
class PersonTest < ActiveSupport::TestCase
  should have_one(:car).through(:partner).source(:vehicle)
end
validate

Use validate to assert that the the :validate option was specified.

class Person < ActiveRecord::Base
  has_one :parking_card, validate: false
end

# RSpec
describe Person do
  it { should have_one(:parking_card).validate(false) }
end

# Test::Unit
class PersonTest < ActiveSupport::TestCase
  should have_one(:parking_card).validate(false)
end

autosave

Use autosave to assert that the :autosave option was specified.

class Account < ActiveRecord::Base
  has_one :bank, autosave: true
end

# RSpec
describe Account do
  it { should have_one(:bank).autosave(true) }
end

# Test::Unit
class AccountTest < ActiveSupport::TestCase
  should have_one(:bank).autosave(true)
end


608
609
610
# File 'lib/shoulda/matchers/active_record/association_matcher.rb', line 608

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

- (HaveReadonlyAttributeMatcher) have_readonly_attribute(value)

The have_readonly_attribute matcher tests usage of the attr_readonly macro.

class User < ActiveRecord::Base
  attr_readonly :password
end

# RSpec
describe User do
  it { should have_readonly_attribute(:password) }
end

# Test::Unit
class UserTest < ActiveSupport::TestCase
  should have_readonly_attribute(:password)
end


23
24
25
# File 'lib/shoulda/matchers/active_record/have_readonly_attribute_matcher.rb', line 23

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

- (SerializeMatcher) serialize(name)

The serialize matcher tests usage of the serialize macro.

class Product < ActiveRecord::Base
  serialize :customizations
end

# RSpec
describe Product do
  it { should serialize(:customizations) }
end

# Test::Unit
class ProductTest < ActiveSupport::TestCase
  should serialize(:customizations)
end

Qualifiers

as

Use as if you are using a custom serializer class.

class ProductSpecsSerializer
  def load(string)
    # ...
  end

  def dump(options)
    # ...
  end
end

class Product < ActiveRecord::Base
  serialize :specifications, ProductSpecsSerializer
end

# RSpec
describe Product do
  it do
    should serialize(:specifications).
      as(ProductSpecsSerializer)
  end
end

# Test::Unit
class ProductTest < ActiveSupport::TestCase
  should serialize(:specifications).
    as(ProductSpecsSerializer)
end
as_instance_of

Use as_instance_of if you are using a custom serializer object.

class ProductOptionsSerializer
  def load(string)
    # ...
  end

  def dump(options)
    # ...
  end
end

class Product < ActiveRecord::Base
  serialize :options, ProductOptionsSerializer.new
end

# RSpec
describe Product do
  it do
    should serialize(:options).
      as_instance_of(ProductOptionsSerializer)
  end
end

# Test::Unit
class ProductTest < ActiveSupport::TestCase
  should serialize(:options).
    as_instance_of(ProductOptionsSerializer)
end


88
89
90
# File 'lib/shoulda/matchers/active_record/serialize_matcher.rb', line 88

def serialize(name)
  SerializeMatcher.new(name)
end