Module: Shoulda::Matchers::ActiveRecord
- Defined in:
- lib/shoulda/matchers/active_record.rb,
lib/shoulda/matchers/active_record/uniqueness.rb,
lib/shoulda/matchers/active_record/encrypt_matcher.rb,
lib/shoulda/matchers/active_record/uniqueness/model.rb,
lib/shoulda/matchers/active_record/normalize_matcher.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/uniqueness/namespace.rb,
lib/shoulda/matchers/active_record/have_attached_matcher.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/have_rich_text_matcher.rb,
lib/shoulda/matchers/active_record/uniqueness/test_models.rb,
lib/shoulda/matchers/active_record/define_enum_for_matcher.rb,
lib/shoulda/matchers/active_record/have_secure_token_matcher.rb,
lib/shoulda/matchers/active_record/have_implicit_order_column.rb,
lib/shoulda/matchers/active_record/uniqueness/test_model_creator.rb,
lib/shoulda/matchers/active_record/validate_uniqueness_of_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/accept_nested_attributes_for_matcher.rb,
lib/shoulda/matchers/active_record/association_matchers/model_reflector.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/association_matchers/model_reflection.rb,
lib/shoulda/matchers/active_record/association_matchers/optional_matcher.rb,
lib/shoulda/matchers/active_record/association_matchers/required_matcher.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
Overview
This module provides matchers that are used to test behavior within ActiveRecord classes.
Defined Under Namespace
Modules: AssociationMatchers, Uniqueness Classes: AcceptNestedAttributesForMatcher, AssociationMatcher, DefineEnumForMatcher, EncryptMatcher, HaveAttachedMatcher, HaveDbColumnMatcher, HaveDbIndexMatcher, HaveImplicitOrderColumnMatcher, HaveReadonlyAttributeMatcher, HaveRichTextMatcher, HaveSecureTokenMatcher, NormalizeMatcher, SerializeMatcher, ValidateUniquenessOfMatcher
Instance Method Summary collapse
-
#accept_nested_attributes_for(name) ⇒ AcceptNestedAttributesForMatcher
The ‘accept_nested_attributes_for` matcher tests usage of the `accepts_nested_attributes_for` macro.
-
#belong_to(name) ⇒ AssociationMatcher
The ‘belong_to` matcher is used to ensure that a `belong_to` association exists on your model.
-
#define_enum_for(attribute_name) ⇒ DefineEnumForMatcher
The ‘define_enum_for` matcher is used to test that the `enum` macro has been used to decorate an attribute with enum capabilities.
-
#encrypt(value) ⇒ EncryptMatcher
The ‘encrypt` matcher tests usage of the `encrypts` macro (Rails 7+ only).
-
#have_and_belong_to_many(name) ⇒ AssociationMatcher
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.
-
#have_db_column(column) ⇒ HaveDbColumnMatcher
The ‘have_db_column` matcher tests that the table that backs your model has a specific column.
-
#have_db_index(columns) ⇒ HaveDbIndexMatcher
The ‘have_db_index` matcher tests that the table that backs your model has a specific index.
-
#have_delegated_type(name) ⇒ AssociationMatcher
The ‘have_delegated_type` matcher is used to ensure that a `belong_to` association exists on your model using the delegated_type macro.
-
#have_implicit_order_column(column_name) ⇒ HaveImplicitOrderColumnMatcher
The ‘have_implicit_order_column` matcher tests that the model has `implicit_order_column` assigned to one of the table columns.
-
#have_many(name) ⇒ AssociationMatcher
The ‘have_many` matcher is used to test that a `has_many` or `has_many :through` association exists on your model.
-
#have_many_attached(name) ⇒ HaveAttachedMatcher
The ‘have_many_attached` matcher tests usage of the `has_many_attached` macro.
-
#have_one(name) ⇒ AssociationMatcher
The ‘have_one` matcher is used to test that a `has_one` or `has_one :through` association exists on your model.
-
#have_one_attached(name) ⇒ HaveAttachedMatcher
The ‘have_one_attached` matcher tests usage of the `has_one_attached` macro.
-
#have_readonly_attribute(value) ⇒ HaveReadonlyAttributeMatcher
The ‘have_readonly_attribute` matcher tests usage of the `attr_readonly` macro.
-
#have_rich_text(rich_text_attribute) ⇒ HaveRichTextMatcher
The ‘have_rich_text` matcher tests usage of the `has_rich_text` macro.
-
#have_secure_token(token_attribute = :token) ⇒ HaveSecureToken
The ‘have_secure_token` matcher tests usage of the `has_secure_token` macro.
-
#normalize(*attributes) ⇒ NormalizeMatcher
The ‘normalize` matcher is used to ensure attribute normalizations are transforming attribute values as expected.
-
#serialize(name) ⇒ SerializeMatcher
The ‘serialize` matcher tests usage of the `serialize` macro.
-
#validate_uniqueness_of(attr) ⇒ ValidateUniquenessOfMatcher
The ‘validate_uniqueness_of` matcher tests usage of the `validates_uniqueness_of` validation.
Instance Method Details
#accept_nested_attributes_for(name) ⇒ AcceptNestedAttributesForMatcher
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
RSpec.describe Car, type: :model do
it { should accept_nested_attributes_for(:doors) }
end
# Minitest (Shoulda) (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
RSpec.describe Car, type: :model do
it do
should accept_nested_attributes_for(:mirrors).
allow_destroy(true)
end
end
# Minitest (Shoulda)
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
RSpec.describe Car, type: :model do
it do
should accept_nested_attributes_for(:windows).
limit(3)
end
end
# Minitest (Shoulda)
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
RSpec.describe Car, type: :model do
it do
should accept_nested_attributes_for(:engine).
update_only(true)
end
end
# Minitest (Shoulda)
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 |
#belong_to(name) ⇒ AssociationMatcher
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
RSpec.describe Person, type: :model do
it { should belong_to(:organization) }
end
# Minitest (Shoulda)
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
RSpec.describe Comment, type: :model do
it { should belong_to(:commentable) }
end
# Minitest (Shoulda)
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
RSpec.describe Person, type: :model do
it do
should belong_to(:family).
conditions(everyone_is_perfect: false)
end
end
# Minitest (Shoulda)
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
RSpec.describe Person, type: :model do
it { should belong_to(:previous_company).order('hired_on desc') }
end
# Minitest (Shoulda)
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
RSpec.describe Person, type: :model do
it { should belong_to(:ancient_city).class_name('City') }
end
# Minitest (Shoulda)
class PersonTest < ActiveSupport::TestCase
should belong_to(:ancient_city).class_name('City')
end
##### with_primary_key
Use ‘with_primary_key` to test usage of the `:primary_key` option.
class Person < ActiveRecord::Base
belongs_to :great_country, primary_key: 'country_id'
end
# RSpec
RSpec.describe Person, type: :model do
it do
should belong_to(:great_country).
with_primary_key('country_id')
end
end
# Minitest (Shoulda)
class PersonTest < ActiveSupport::TestCase
should belong_to(:great_country).
with_primary_key('country_id')
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
RSpec.describe Person, type: :model do
it do
should belong_to(:great_country).
with_foreign_key('country_id')
end
end
# Minitest (Shoulda)
class PersonTest < ActiveSupport::TestCase
should belong_to(:great_country).
with_foreign_key('country_id')
end
##### with_foreign_type
Use ‘with_foreign_type` to test usage of the `:foreign_type` option.
class Visitor < ActiveRecord::Base
belongs_to :location, foreign_type: 'facility_type', polymorphic: true
end
# RSpec
RSpec.describe Visitor, type: :model do
it do
should belong_to(:location).
with_foreign_type('facility_type')
end
end
# Minitest (Shoulda)
class VisitorTest < ActiveSupport::TestCase
should belong_to(:location).
with_foreign_type('facility_type')
end
##### dependent
Use ‘dependent` to assert that the `:dependent` option was specified.
class Person < ActiveRecord::Base
belongs_to :world, dependent: :destroy
end
# RSpec
RSpec.describe Person, type: :model do
it { should belong_to(:world).dependent(:destroy) }
end
# Minitest (Shoulda)
class PersonTest < ActiveSupport::TestCase
should belong_to(:world).dependent(:destroy)
end
To assert that any ‘:dependent` option was specified, use `true`:
# RSpec
RSpec.describe Person, type: :model do
it { should belong_to(:world).dependent(true) }
end
To assert that no ‘:dependent` option was specified, use `false`:
class Person < ActiveRecord::Base
belongs_to :company
end
# RSpec
RSpec.describe Person, type: :model do
it { should belong_to(:company).dependent(false) }
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
RSpec.describe Person, type: :model do
it { should belong_to(:organization).counter_cache(true) }
end
# Minitest (Shoulda)
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
RSpec.describe Person, type: :model do
it { should belong_to(:organization).touch(true) }
end
# Minitest (Shoulda)
class PersonTest < ActiveSupport::TestCase
should belong_to(:organization).touch(true)
end
##### strict_loading
Use ‘strict_loading` to assert that the `:strict_loading` option was specified.
class Organization < ActiveRecord::Base
has_many :people, strict_loading: true
end
# RSpec
RSpec.describe Organization, type: :model do
it { should have_many(:people).strict_loading(true) }
end
# Minitest (Shoulda)
class OrganizationTest < ActiveSupport::TestCase
should have_many(:people).strict_loading(true)
end
Default value is true when no argument is specified
# RSpec
RSpec.describe Organization, type: :model do
it { should have_many(:people).strict_loading }
end
# Minitest (Shoulda)
class OrganizationTest < ActiveSupport::TestCase
should have_many(:people).strict_loading
end
##### autosave
Use ‘autosave` to assert that the `:autosave` option was specified.
class Account < ActiveRecord::Base
belongs_to :bank, autosave: true
end
# RSpec
RSpec.describe Account, type: :model do
it { should belong_to(:bank).autosave(true) }
end
# Minitest (Shoulda)
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
# Minitest (Shoulda)
class PersonTest < ActiveSupport::TestCase
should belong_to(:organization).inverse_of(:employees)
end
##### required
Use ‘required` to assert that the association is not allowed to be nil. (Enabled by default in Rails 5+.)
class Person < ActiveRecord::Base
belongs_to :organization, required: true
end
# RSpec
describe Person
it { should belong_to(:organization).required }
end
# Minitest (Shoulda)
class PersonTest < ActiveSupport::TestCase
should belong_to(:organization).required
end
##### without_validating_presence
Use ‘without_validating_presence` with `belong_to` to prevent the matcher from checking whether the association disallows nil (Rails 5+ only). This can be helpful if you have a custom hook that always sets the association to a meaningful value:
class Person < ActiveRecord::Base
belongs_to :organization
before_validation :autoassign_organization
private
def autoassign_organization
self.organization = Organization.create!
end
end
# RSpec
describe Person
it { should belong_to(:organization).without_validating_presence }
end
# Minitest (Shoulda)
class PersonTest < ActiveSupport::TestCase
should belong_to(:organization).without_validating_presence
end
##### optional
Use ‘optional` to assert that the association is allowed to be nil. (Rails 5+ only.)
class Person < ActiveRecord::Base
belongs_to :organization, optional: true
end
# RSpec
describe Person
it { should belong_to(:organization).optional }
end
# Minitest (Shoulda)
class PersonTest < ActiveSupport::TestCase
should belong_to(:organization).optional
end
377 378 379 |
# File 'lib/shoulda/matchers/active_record/association_matcher.rb', line 377 def belong_to(name) AssociationMatcher.new(:belongs_to, name) end |
#define_enum_for(attribute_name) ⇒ DefineEnumForMatcher
The ‘define_enum_for` matcher is used to test that the `enum` macro has been used to decorate an attribute with enum capabilities.
class Process < ActiveRecord::Base
enum status: [:running, :stopped, :suspended]
alias_attribute :kind, :SomeLegacyField
enum kind: [:foo, :bar]
end
# RSpec
RSpec.describe Process, type: :model do
it { should define_enum_for(:status) }
it { should define_enum_for(:kind) }
end
# Minitest (Shoulda)
class ProcessTest < ActiveSupport::TestCase
should define_enum_for(:status)
should define_enum_for(:kind)
end
#### Qualifiers
##### with_values
Use ‘with_values` to test that the attribute can only receive a certain set of possible values.
class Process < ActiveRecord::Base
enum status: [:running, :stopped, :suspended]
end
# RSpec
RSpec.describe Process, type: :model do
it do
should define_enum_for(:status).
with_values([:running, :stopped, :suspended])
end
end
# Minitest (Shoulda)
class ProcessTest < ActiveSupport::TestCase
should define_enum_for(:status).
with_values([:running, :stopped, :suspended])
end
If the values backing your enum attribute are arbitrary instead of a series of integers starting from 0, pass a hash to ‘with_values` instead of an array:
class Process < ActiveRecord::Base
enum status: {
running: 0,
stopped: 1,
suspended: 3,
other: 99
}
end
# RSpec
RSpec.describe Process, type: :model do
it do
should define_enum_for(:status).
with_values(running: 0, stopped: 1, suspended: 3, other: 99)
end
end
# Minitest (Shoulda)
class ProcessTest < ActiveSupport::TestCase
should define_enum_for(:status).
with_values(running: 0, stopped: 1, suspended: 3, other: 99)
end
##### backed_by_column_of_type
Use ‘backed_by_column_of_type` when the column backing your column type is a string instead of an integer:
class LoanApplication < ActiveRecord::Base
enum status: {
active: "active",
pending: "pending",
rejected: "rejected"
}
end
# RSpec
RSpec.describe LoanApplication, type: :model do
it do
should define_enum_for(:status).
with_values(
active: "active",
pending: "pending",
rejected: "rejected"
).
backed_by_column_of_type(:string)
end
end
# Minitest (Shoulda)
class LoanApplicationTest < ActiveSupport::TestCase
should define_enum_for(:status).
with_values(
active: "active",
pending: "pending",
rejected: "rejected"
).
backed_by_column_of_type(:string)
end
##### with_prefix
Use ‘with_prefix` to test that the enum is defined with a `_prefix` option (Rails 6+ only). Can take either a boolean or a symbol:
class Issue < ActiveRecord::Base
enum status: [:open, :closed], _prefix: :old
end
# RSpec
RSpec.describe Issue, type: :model do
it do
should define_enum_for(:status).
with_values([:open, :closed]).
with_prefix(:old)
end
end
# Minitest (Shoulda)
class ProcessTest < ActiveSupport::TestCase
should define_enum_for(:status).
with_values([:open, :closed]).
with_prefix(:old)
end
##### with_suffix
Use ‘with_suffix` to test that the enum is defined with a `_suffix` option (Rails 5 only). Can take either a boolean or a symbol:
class Issue < ActiveRecord::Base
enum status: [:open, :closed], _suffix: true
end
# RSpec
RSpec.describe Issue, type: :model do
it do
should define_enum_for(:status).
with_values([:open, :closed]).
with_suffix
end
end
# Minitest (Shoulda)
class ProcessTest < ActiveSupport::TestCase
should define_enum_for(:status).
with_values([:open, :closed]).
with_suffix
end
##### without_scopes
Use ‘without_scopes` to test that the enum is defined with ’_scopes: false’ option (Rails 5 only). Can take either a boolean or a symbol:
class Issue < ActiveRecord::Base
enum status: [:open, :closed], _scopes: false
end
# RSpec
RSpec.describe Issue, type: :model do
it do
should define_enum_for(:status).
without_scopes
end
end
# Minitest (Shoulda)
class ProcessTest < ActiveSupport::TestCase
should define_enum_for(:status).
without_scopes
end
##### with_default
Use ‘with_default` to test that the enum is defined with a default value. A proc can also be passed, and will be called once each time a new value is needed. (If using Time or Date, it’s recommended to freeze time or date to avoid flaky tests):
class Issue < ActiveRecord::Base
enum status: [:open, :closed], default: :closed
end
# RSpec
RSpec.describe Issue, type: :model do
it do
should define_enum_for(:status).
with_default(:closed)
end
end
# Minitest (Shoulda)
class ProcessTest < ActiveSupport::TestCase
should define_enum_for(:status).
with_default(:closed)
end
##### validating
Use ‘validating` to test that the enum is being validated. Can take a boolean value and an allowing_nil keyword argument:
class Issue < ActiveRecord::Base
enum status: [:open, :closed], validate: true
end
# RSpec
RSpec.describe Issue, type: :model do
it do
should define_enum_for(:status).
validating
end
end
# Minitest (Shoulda)
class ProcessTest < ActiveSupport::TestCase
should define_enum_for(:status).
validating
end
class Issue < ActiveRecord::Base
enum status: [:open, :closed], validate: { allow_nil: true }
end
# RSpec
RSpec.describe Issue, type: :model do
it do
should define_enum_for(:status).
validating(allowing_nil: true)
end
end
# Minitest (Shoulda)
class ProcessTest < ActiveSupport::TestCase
should define_enum_for(:status).
validating(allowing_nil: true)
end
##### without_instance_methods
Use ‘without_instance_methods` to exclude the check for instance methods.
class Issue < ActiveRecord::Base
enum status: [:open, :closed], instance_methods: false
end
# RSpec
RSpec.describe Issue, type: :model do
it do
should define_enum_for(:status).
without_instance_methods
end
end
# Minitest (Shoulda)
class ProcessTest < ActiveSupport::TestCase
should define_enum_for(:status).
without_instance_methods
end
279 280 281 |
# File 'lib/shoulda/matchers/active_record/define_enum_for_matcher.rb', line 279 def define_enum_for(attribute_name) DefineEnumForMatcher.new(attribute_name) end |
#encrypt(value) ⇒ EncryptMatcher
The ‘encrypt` matcher tests usage of the `encrypts` macro (Rails 7+ only).
class Survey < ActiveRecord::Base
encrypts :access_code
end
# RSpec
RSpec.describe Survey, type: :model do
it { should encrypt(:access_code) }
end
# Minitest (Shoulda)
class SurveyTest < ActiveSupport::TestCase
should encrypt(:access_code)
end
#### Qualifiers
##### deterministic
class Survey < ActiveRecord::Base
encrypts :access_code, deterministic: true
end
# RSpec
RSpec.describe Survey, type: :model do
it { should encrypt(:access_code).deterministic(true) }
end
# Minitest (Shoulda)
class SurveyTest < ActiveSupport::TestCase
should encrypt(:access_code).deterministic(true)
end
##### downcase
class Survey < ActiveRecord::Base
encrypts :access_code, downcase: true
end
# RSpec
RSpec.describe Survey, type: :model do
it { should encrypt(:access_code).downcase(true) }
end
# Minitest (Shoulda)
class SurveyTest < ActiveSupport::TestCase
should encrypt(:access_code).downcase(true)
end
##### ignore_case
class Survey < ActiveRecord::Base
encrypts :access_code, deterministic: true, ignore_case: true
end
# RSpec
RSpec.describe Survey, type: :model do
it { should encrypt(:access_code).ignore_case(true) }
end
# Minitest (Shoulda)
class SurveyTest < ActiveSupport::TestCase
should encrypt(:access_code).ignore_case(true)
end
73 74 75 |
# File 'lib/shoulda/matchers/active_record/encrypt_matcher.rb', line 73 def encrypt(value) EncryptMatcher.new(value) end |
#have_and_belong_to_many(name) ⇒ AssociationMatcher
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
RSpec.describe Person, type: :model do
it { should have_and_belong_to_many(:awards) }
end
# Minitest (Shoulda)
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
RSpec.describe Person, type: :model do
it do
should have_and_belong_to_many(:issues).
conditions(difficulty: 'hard')
end
end
# Minitest (Shoulda)
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
RSpec.describe Person, type: :model do
it do
should have_and_belong_to_many(:projects).
order('time_spent')
end
end
# Minitest (Shoulda)
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
RSpec.describe Person, type: :model do
it do
should have_and_belong_to_many(:places_visited).
class_name('City')
end
end
# Minitest (Shoulda)
class PersonTest < ActiveSupport::TestCase
should have_and_belong_to_many(:places_visited).
class_name('City')
end
##### join_table
Use ‘join_table` to test usage of the `:join_table` option. This asserts that the table you’re referring to actually exists.
class Person < ActiveRecord::Base
has_and_belongs_to_many :issues, join_table: :people_tickets
end
# RSpec
RSpec.describe Person, type: :model do
it do
should have_and_belong_to_many(:issues).
join_table(:people_tickets)
end
end
# Minitest (Shoulda)
class PersonTest < ActiveSupport::TestCase
should have_and_belong_to_many(:issues).
join_table(:people_tickets)
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
RSpec.describe Person, type: :model do
it do
should have_and_belong_to_many(:interviews).
validate(false)
end
end
# Minitest (Shoulda)
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
RSpec.describe Publisher, type: :model do
it { should have_and_belong_to_many(:advertisers).autosave(true) }
end
# Minitest (Shoulda)
class AccountTest < ActiveSupport::TestCase
should have_and_belong_to_many(:advertisers).autosave(true)
end
1380 1381 1382 |
# File 'lib/shoulda/matchers/active_record/association_matcher.rb', line 1380 def have_and_belong_to_many(name) AssociationMatcher.new(:has_and_belongs_to_many, name) end |
#have_db_column(column) ⇒ HaveDbColumnMatcher
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
RSpec.describe Phone, type: :model do
it { should have_db_column(:supported_ios_version) }
end
# Minitest (Shoulda)
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
RSpec.describe Phone, type: :model do
it do
should have_db_column(:camera_aperture).of_type(:decimal)
end
end
# Minitest (Shoulda)
class PhoneTest < ActiveSupport::TestCase
should have_db_column(:camera_aperture).of_type(:decimal)
end
##### of_sql_type
Use ‘of_sql_type` to assert that a column is defined as a certain sql_type.
class CreatePhones < ActiveRecord::Migration
def change
create_table :phones do |t|
t.string :camera_aperture, limit: 36
end
end
end
# RSpec
RSpec.describe Phone, type: :model do
it do
should have_db_column(:camera_aperture).of_sql_type('varchar(36)')
end
end
# Minitest (Shoulda)
class PhoneTest < ActiveSupport::TestCase
should have_db_column(:camera_aperture).of_sql_type('varchar(36)')
end
##### with_options
Use ‘with_options` to assert that a column has been defined with certain options (`:precision`, `:limit`, `:default`, `:null`, `:scale`, `:primary` or `:array`).
class CreatePhones < ActiveRecord::Migration
def change
create_table :phones do |t|
t.decimal :camera_aperture, precision: 1, null: false
end
end
end
# RSpec
RSpec.describe Phone, type: :model do
it do
should have_db_column(:camera_aperture).
(precision: 1, null: false)
end
end
# Minitest (Shoulda)
class PhoneTest < ActiveSupport::TestCase
should have_db_column(:camera_aperture).
(precision: 1, null: false)
end
105 106 107 |
# File 'lib/shoulda/matchers/active_record/have_db_column_matcher.rb', line 105 def have_db_column(column) HaveDbColumnMatcher.new(column) end |
#have_db_index(columns) ⇒ HaveDbIndexMatcher
The ‘have_db_index` matcher tests that the table that backs your model has a specific index.
You can specify one 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
RSpec.describe Blog, type: :model do
it { should have_db_index(:user_id) }
end
# Minitest (Shoulda)
class BlogTest < ActiveSupport::TestCase
should have_db_index(:user_id)
end
Or you can specify a group of columns:
class CreateBlogs < ActiveRecord::Migration
def change
create_table :blogs do |t|
t.integer :user_id
t.string :name
end
add_index :blogs, :user_id, :name
end
end
# RSpec
RSpec.describe Blog, type: :model do
it { should have_db_index([:user_id, :name]) }
end
# Minitest (Shoulda)
class BlogTest < ActiveSupport::TestCase
should have_db_index([:user_id, :name])
end
Finally, if you’re using Rails 5 and PostgreSQL, you can also specify an expression:
class CreateLoggedErrors < ActiveRecord::Migration
def change
create_table :logged_errors do |t|
t.string :code
t.jsonb :content
end
add_index :logged_errors, 'lower(code)::text'
end
end
# RSpec
RSpec.describe LoggedError, type: :model do
it { should have_db_index('lower(code)::text') }
end
# Minitest (Shoulda)
class LoggedErrorTest < ActiveSupport::TestCase
should have_db_index('lower(code)::text')
end
#### Qualifiers
##### unique
Use ‘unique` to assert that the index is either unique or non-unique:
class CreateBlogs < ActiveRecord::Migration
def change
create_table :blogs do |t|
t.string :domain
t.integer :user_id
end
add_index :blogs, :domain, unique: true
add_index :blogs, :user_id
end
end
# RSpec
RSpec.describe Blog, type: :model do
it { should have_db_index(:name).unique }
it { should have_db_index(:name).unique(true) } # if you want to be explicit
it { should have_db_index(:user_id).unique(false) }
end
# Minitest (Shoulda)
class BlogTest < ActiveSupport::TestCase
should have_db_index(:name).unique
should have_db_index(:name).unique(true) # if you want to be explicit
should have_db_index(:user_id).unique(false)
end
110 111 112 |
# File 'lib/shoulda/matchers/active_record/have_db_index_matcher.rb', line 110 def have_db_index(columns) HaveDbIndexMatcher.new(columns) end |
#have_delegated_type(name) ⇒ AssociationMatcher
The ‘have_delegated_type` matcher is used to ensure that a `belong_to` association exists on your model using the delegated_type macro.
class Vehicle < ActiveRecord::Base
delegated_type :drivable, types: %w(Car Truck)
end
# RSpec
RSpec.describe Vehicle, type: :model do
it { should have_delegated_type(:drivable) }
end
# Minitest (Shoulda)
class VehicleTest < ActiveSupport::TestCase
should have_delegated_type(:drivable)
end
#### Qualifiers
##### types
Use ‘types` to test the types that are allowed for the association.
class Vehicle < ActiveRecord::Base
delegated_type :drivable, types: %w(Car Truck)
end
# RSpec
RSpec.describe Vehicle, type: :model do
it do
should have_delegated_type(:drivable).
types(%w(Car Truck))
end
end
# Minitest (Shoulda)
class VehicleTest < ActiveSupport::TestCase
should have_delegated_type(:drivable).
types(%w(Car Truck))
end
##### conditions
Use ‘conditions` if your association is defined with a scope that sets the `where` clause.
class Vehicle < ActiveRecord::Base
delegated_type :drivable, types: %w(Car Truck), scope: -> { where(with_wheels: true) }
end
# RSpec
RSpec.describe Vehicle, type: :model do
it do
should have_delegated_type(:drivable).
conditions(with_wheels: true)
end
end
# Minitest (Shoulda)
class VehicleTest < ActiveSupport::TestCase
should have_delegated_type(:drivable).
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
delegated_type :drivable, types: %w(Car Truck), scope: -> { order('wheels desc') }
end
# RSpec
RSpec.describe Vehicle, type: :model do
it { should have_delegated_type(:drivable).order('wheels desc') }
end
# Minitest (Shoulda)
class VehicleTest < ActiveSupport::TestCase
should have_delegated_type(:drivable).order('wheels desc')
end
##### with_primary_key
Use ‘with_primary_key` to test usage of the `:primary_key` option.
class Vehicle < ActiveRecord::Base
delegated_type :drivable, types: %w(Car Truck), primary_key: 'vehicle_id'
end
# RSpec
RSpec.describe Vehicle, type: :model do
it do
should have_delegated_type(:drivable).
with_primary_key('vehicle_id')
end
end
# Minitest (Shoulda)
class VehicleTest < ActiveSupport::TestCase
should have_delegated_type(:drivable).
with_primary_key('vehicle_id')
end
##### with_foreign_key
Use ‘with_foreign_key` to test usage of the `:foreign_key` option.
class Vehicle < ActiveRecord::Base
delegated_type :drivable, types: %w(Car Truck), foreign_key: 'drivable_uuid'
end
# RSpec
RSpec.describe Vehicle, type: :model do
it do
should have_delegated_type(:drivable).
with_foreign_key('drivable_uuid')
end
end
# Minitest (Shoulda)
class VehicleTest < ActiveSupport::TestCase
should have_delegated_type(:drivable).
with_foreign_key('drivable_uuid')
end
##### dependent
Use ‘dependent` to assert that the `:dependent` option was specified.
class Vehicle < ActiveRecord::Base
delegated_type :drivable, types: %w(Car Truck), dependent: :destroy
end
# RSpec
RSpec.describe Vehicle, type: :model do
it { should have_delegated_type(:drivable).dependent(:destroy) }
end
# Minitest (Shoulda)
class VehicleTest < ActiveSupport::TestCase
should have_delegated_type(:drivable).dependent(:destroy)
end
To assert that any ‘:dependent` option was specified, use `true`:
# RSpec
RSpec.describe Vehicle, type: :model do
it { should have_delegated_type(:drivable).dependent(true) }
end
To assert that no ‘:dependent` option was specified, use `false`:
class Vehicle < ActiveRecord::Base
delegated_type :drivable, types: %w(Car Truck)
end
# RSpec
RSpec.describe Vehicle, type: :model do
it { should have_delegated_type(:drivable).dependent(false) }
end
##### counter_cache
Use ‘counter_cache` to assert that the `:counter_cache` option was specified.
class Vehicle < ActiveRecord::Base
delegated_type :drivable, types: %w(Car Truck), counter_cache: true
end
# RSpec
RSpec.describe Vehicle, type: :model do
it { should have_delegated_type(:drivable).counter_cache(true) }
end
# Minitest (Shoulda)
class VehicleTest < ActiveSupport::TestCase
should have_delegated_type(:drivable).counter_cache(true)
end
##### touch
Use ‘touch` to assert that the `:touch` option was specified.
class Vehicle < ActiveRecord::Base
delegated_type :drivable, types: %w(Car Truck), touch: true
end
# RSpec
RSpec.describe Vehicle, type: :model do
it { should have_delegated_type(:drivable).touch(true) }
end
# Minitest (Shoulda)
class VehicleTest < ActiveSupport::TestCase
should have_delegated_type(:drivable).touch(true)
end
##### autosave
Use ‘autosave` to assert that the `:autosave` option was specified.
class Vehicle < ActiveRecord::Base
delegated_type :drivable, types: %w(Car Truck), autosave: true
end
# RSpec
RSpec.describe Vehicle, type: :model do
it { should have_delegated_type(:drivable).autosave(true) }
end
# Minitest (Shoulda)
class VehicleTest < ActiveSupport::TestCase
should have_delegated_type(:drivable).autosave(true)
end
##### inverse_of
Use ‘inverse_of` to assert that the `:inverse_of` option was specified.
class Vehicle < ActiveRecord::Base
delegated_type :drivable, types: %w(Car Truck), inverse_of: :vehicle
end
# RSpec
describe Vehicle
it { should have_delegated_type(:drivable).inverse_of(:vehicle) }
end
# Minitest (Shoulda)
class VehicleTest < ActiveSupport::TestCase
should have_delegated_type(:drivable).inverse_of(:vehicle)
end
##### required
Use ‘required` to assert that the association is not allowed to be nil. (Enabled by default in Rails 5+.)
class Vehicle < ActiveRecord::Base
delegated_type :drivable, types: %w(Car Truck), required: true
end
# RSpec
describe Vehicle
it { should have_delegated_type(:drivable).required }
end
# Minitest (Shoulda)
class VehicleTest < ActiveSupport::TestCase
should have_delegated_type(:drivable).required
end
##### without_validating_presence
Use ‘without_validating_presence` with `belong_to` to prevent the matcher from checking whether the association disallows nil (Rails 5+ only). This can be helpful if you have a custom hook that always sets the association to a meaningful value:
class Vehicle < ActiveRecord::Base
delegated_type :drivable, types: %w(Car Truck)
before_validation :autoassign_drivable
private
def autoassign_drivable
self.drivable = Car.create!
end
end
# RSpec
describe Vehicle
it { should have_delegated_type(:drivable).without_validating_presence }
end
# Minitest (Shoulda)
class VehicleTest < ActiveSupport::TestCase
should have_delegated_type(:drivable).without_validating_presence
end
##### optional
Use ‘optional` to assert that the association is allowed to be nil. (Rails 5+ only.)
class Vehicle < ActiveRecord::Base
delegated_type :drivable, types: %w(Car Truck), optional: true
end
# RSpec
describe Vehicle
it { should have_delegated_type(:drivable).optional }
end
# Minitest (Shoulda)
class VehicleTest < ActiveSupport::TestCase
should have_delegated_type(:drivable).optional
end
687 688 689 |
# File 'lib/shoulda/matchers/active_record/association_matcher.rb', line 687 def have_delegated_type(name) AssociationMatcher.new(:belongs_to, name) end |
#have_implicit_order_column(column_name) ⇒ HaveImplicitOrderColumnMatcher
The ‘have_implicit_order_column` matcher tests that the model has `implicit_order_column` assigned to one of the table columns.
class Product < ApplicationRecord
self.implicit_order_column = :created_at
end
# RSpec
RSpec.describe Product, type: :model do
it { should have_implicit_order_column(:created_at) }
end
# Minitest (Shoulda)
class ProductTest < ActiveSupport::TestCase
should have_implicit_order_column(:created_at)
end
23 24 25 |
# File 'lib/shoulda/matchers/active_record/have_implicit_order_column.rb', line 23 def have_implicit_order_column(column_name) HaveImplicitOrderColumnMatcher.new(column_name) end |
#have_many(name) ⇒ AssociationMatcher
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
RSpec.describe Person, type: :model do
it { should have_many(:friends) }
end
# Minitest (Shoulda)
class PersonTest < ActiveSupport::TestCase
should have_many(:friends)
end
Note that polymorphic associations are automatically detected and do not need any qualifiers:
class Person < ActiveRecord::Base
has_many :pictures, as: :imageable
end
# RSpec
RSpec.describe Person, type: :model do
it { should have_many(:pictures) }
end
# Minitest (Shoulda)
class PersonTest < ActiveSupport::TestCase
should have_many(:pictures)
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
RSpec.describe Person, type: :model do
it { should have_many(:coins).conditions(quality: 'mint') }
end
# Minitest (Shoulda)
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
RSpec.describe Person, type: :model do
it { should have_many(:shirts).order('color') }
end
# Minitest (Shoulda)
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
RSpec.describe Person, type: :model do
it { should have_many(:hopes).class_name('Dream') }
end
# Minitest (Shoulda)
class PersonTest < ActiveSupport::TestCase
should have_many(:hopes).class_name('Dream')
end
##### with_primary_key
Use ‘with_primary_key` to test usage of the `:primary_key` option.
class Person < ActiveRecord::Base
has_many :worries, primary_key: 'worrier_id'
end
# RSpec
RSpec.describe Person, type: :model do
it { should have_many(:worries).with_primary_key('worrier_id') }
end
# Minitest (Shoulda)
class PersonTest < ActiveSupport::TestCase
should have_many(:worries).with_primary_key('worrier_id')
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
RSpec.describe Person, type: :model do
it { should have_many(:worries).with_foreign_key('worrier_id') }
end
# Minitest (Shoulda)
class PersonTest < ActiveSupport::TestCase
should have_many(:worries).with_foreign_key('worrier_id')
end
##### with_foreign_type
Use ‘with_foreign_type` to test usage of the `:foreign_type` option.
class Hotel < ActiveRecord::Base
has_many :visitors, foreign_key: 'facility_type', as: :location
end
# RSpec
RSpec.describe Hotel, type: :model do
it { should have_many(:visitors).with_foreign_type('facility_type') }
end
# Minitest (Shoulda)
class HotelTest < ActiveSupport::TestCase
should have_many(:visitors).with_foreign_type('facility_type')
end
##### dependent
Use ‘dependent` to assert that the `:dependent` option was specified.
class Person < ActiveRecord::Base
has_many :secret_documents, dependent: :destroy
end
# RSpec
RSpec.describe Person, type: :model do
it { should have_many(:secret_documents).dependent(:destroy) }
end
# Minitest (Shoulda)
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
RSpec.describe Person, type: :model do
it { should have_many(:acquaintances).through(:friends) }
end
# Minitest (Shoulda)
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
RSpec.describe Person, type: :model do
it do
should have_many(:job_offers).
through(:friends).
source(:opportunities)
end
end
# Minitest (Shoulda)
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
RSpec.describe Person, type: :model do
it { should have_many(:ideas).validate(false) }
end
# Minitest (Shoulda)
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
RSpec.describe Player, type: :model do
it { should have_many(:games).autosave(true) }
end
# Minitest (Shoulda)
class PlayerTest < ActiveSupport::TestCase
should have_many(:games).autosave(true)
end
##### index_errors
Use ‘index_errors` to assert that the `:index_errors` option was specified.
class Player < ActiveRecord::Base
has_many :games, index_errors: true
end
# RSpec
RSpec.describe Player, type: :model do
it { should have_many(:games).index_errors(true) }
end
# Minitest (Shoulda)
class PlayerTest < ActiveSupport::TestCase
should have_many(:games).index_errors(true)
end
##### inverse_of
Use ‘inverse_of` to assert that the `:inverse_of` option was specified.
class Organization < ActiveRecord::Base
has_many :employees, inverse_of: :company
end
# RSpec
describe Organization
it { should have_many(:employees).inverse_of(:company) }
end
# Minitest (Shoulda)
class OrganizationTest < ActiveSupport::TestCase
should have_many(:employees).inverse_of(:company)
end
975 976 977 |
# File 'lib/shoulda/matchers/active_record/association_matcher.rb', line 975 def have_many(name) AssociationMatcher.new(:has_many, name) end |
#have_many_attached(name) ⇒ HaveAttachedMatcher
The ‘have_many_attached` matcher tests usage of the `has_many_attached` macro.
#### Example
class Message < ApplicationRecord
has_many_attached :images
end
# RSpec
RSpec.describe Message, type: :model do
it { should have_many_attached(:images) }
end
# Minitest (Shoulda)
class MessageTest < ActiveSupport::TestCase
should have_many_attached(:images)
end
50 51 52 |
# File 'lib/shoulda/matchers/active_record/have_attached_matcher.rb', line 50 def have_many_attached(name) HaveAttachedMatcher.new(:many, name) end |
#have_one(name) ⇒ AssociationMatcher
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
RSpec.describe Person, type: :model do
it { should have_one(:partner) }
end
# Minitest (Shoulda)
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
RSpec.describe Person, type: :model do
it { should have_one(:pet).conditions('weight < 80') }
end
# Minitest (Shoulda)
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
RSpec.describe Person, type: :model do
it { should have_one(:focus).order('priority desc') }
end
# Minitest (Shoulda)
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
RSpec.describe Person, type: :model do
it { should have_one(:chance).class_name('Opportunity') }
end
# Minitest (Shoulda)
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
RSpec.describe Person, type: :model do
it { should have_one(:contract).dependent(:nullify) }
end
# Minitest (Shoulda)
class PersonTest < ActiveSupport::TestCase
should have_one(:contract).dependent(:nullify)
end
##### with_primary_key
Use ‘with_primary_key` to test usage of the `:primary_key` option.
class Person < ActiveRecord::Base
has_one :job, primary_key: 'worker_id'
end
# RSpec
RSpec.describe Person, type: :model do
it { should have_one(:job).with_primary_key('worker_id') }
end
# Minitest (Shoulda)
class PersonTest < ActiveSupport::TestCase
should have_one(:job).with_primary_key('worker_id')
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
RSpec.describe Person, type: :model do
it { should have_one(:job).with_foreign_key('worker_id') }
end
# Minitest (Shoulda)
class PersonTest < ActiveSupport::TestCase
should have_one(:job).with_foreign_key('worker_id')
end
##### with_foreign_type
Use ‘with_foreign_type` to test usage of the `:foreign_type` option.
class Hotel < ActiveRecord::Base
has_one :special_guest, foreign_type: 'facility_type', as: :location
end
# RSpec
RSpec.describe Hotel, type: :model do
it { should have_one(:special_guest).with_foreign_type('facility_type') }
end
# Minitest (Shoulda)
class HotelTest < ActiveSupport::TestCase
should have_one(:special_guest).with_foreign_type('facility_type')
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
RSpec.describe Person, type: :model do
it { should have_one(:life).through(:partner) }
end
# Minitest (Shoulda)
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
RSpec.describe Person, type: :model do
it { should have_one(:car).through(:partner).source(:vehicle) }
end
# Minitest (Shoulda)
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
RSpec.describe Person, type: :model do
it { should have_one(:parking_card).validate(false) }
end
# Minitest (Shoulda)
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
RSpec.describe Account, type: :model do
it { should have_one(:bank).autosave(true) }
end
# Minitest (Shoulda)
class AccountTest < ActiveSupport::TestCase
should have_one(:bank).autosave(true)
end
##### required
Use ‘required` to assert that the association is not allowed to be nil. (Rails 5+ only.)
class Person < ActiveRecord::Base
has_one :brain, required: true
end
# RSpec
describe Person
it { should have_one(:brain).required }
end
# Minitest (Shoulda)
class PersonTest < ActiveSupport::TestCase
should have_one(:brain).required
end
1222 1223 1224 |
# File 'lib/shoulda/matchers/active_record/association_matcher.rb', line 1222 def have_one(name) AssociationMatcher.new(:has_one, name) end |
#have_one_attached(name) ⇒ HaveAttachedMatcher
The ‘have_one_attached` matcher tests usage of the `has_one_attached` macro.
#### Example
class User < ApplicationRecord
has_one_attached :avatar
end
# RSpec
RSpec.describe User, type: :model do
it { should have_one_attached(:avatar) }
end
# Minitest (Shoulda)
class UserTest < ActiveSupport::TestCase
should have_one_attached(:avatar)
end
25 26 27 |
# File 'lib/shoulda/matchers/active_record/have_attached_matcher.rb', line 25 def have_one_attached(name) HaveAttachedMatcher.new(:one, name) end |
#have_readonly_attribute(value) ⇒ HaveReadonlyAttributeMatcher
The ‘have_readonly_attribute` matcher tests usage of the `attr_readonly` macro.
class User < ActiveRecord::Base
attr_readonly :password
end
# RSpec
RSpec.describe User, type: :model do
it { should have_readonly_attribute(:password) }
end
# Minitest (Shoulda)
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 |
#have_rich_text(rich_text_attribute) ⇒ HaveRichTextMatcher
The ‘have_rich_text` matcher tests usage of the `has_rich_text` macro.
#### Example
class Post < ActiveRecord
has_rich_text :content
end
# RSpec
RSpec.describe Post, type: :model do
it { should have_rich_text(:content) }
end
# Minitest (Shoulda)
class PostTest < ActiveSupport::TestCase
should have_rich_text(:content)
end
25 26 27 |
# File 'lib/shoulda/matchers/active_record/have_rich_text_matcher.rb', line 25 def have_rich_text(rich_text_attribute) HaveRichTextMatcher.new(rich_text_attribute) end |
#have_secure_token(token_attribute = :token) ⇒ HaveSecureToken
The ‘have_secure_token` matcher tests usage of the `has_secure_token` macro.
class User < ActiveRecord
has_secure_token
has_secure_token :auth_token
end
# RSpec
RSpec.describe User, type: :model do
it { should have_secure_token }
it { should have_secure_token(:auth_token) }
end
# Minitest (Shoulda)
class UserTest < ActiveSupport::TestCase
should have_secure_token
should have_secure_token(:auth_token)
end
#### Qualifiers
##### ignoring_check_for_db_index
By default, this matcher tests that an index is defined on your token column. Use ‘ignoring_check_for_db_index` if this is not the case.
class User < ActiveRecord
has_secure_token :auth_token
end
# RSpec
RSpec.describe User, type: :model do
it { should have_secure_token(:auth_token).ignoring_check_for_db_index }
end
# Minitest (Shoulda)
class UserTest < ActiveSupport::TestCase
should have_secure_token(:auth_token).ignoring_check_for_db_index
end
47 48 49 |
# File 'lib/shoulda/matchers/active_record/have_secure_token_matcher.rb', line 47 def have_secure_token(token_attribute = :token) HaveSecureTokenMatcher.new(token_attribute) end |
#normalize(*attributes) ⇒ NormalizeMatcher
The ‘normalize` matcher is used to ensure attribute normalizations are transforming attribute values as expected.
Take this model for example:
class User < ActiveRecord::Base
normalizes :email, with: -> email { email.strip.downcase }
end
You can use ‘normalize` providing an input and defining the expected normalization output:
# RSpec
RSpec.describe User, type: :model do
it do
should normalize(:email).from(" [email protected]\n").to("[email protected]")
end
end
# Minitest (Shoulda)
class User < ActiveSupport::TestCase
should normalize(:email).from(" [email protected]\n").to("[email protected]")
end
You can use ‘normalize` to test multiple attributes at once:
class User < ActiveRecord::Base
normalizes :email, :handle, with: -> value { value.strip.downcase }
end
# RSpec
RSpec.describe User, type: :model do
it do
should normalize(:email, :handle).from(" Example\n").to("example")
end
end
# Minitest (Shoulda)
class User < ActiveSupport::TestCase
should normalize(:email, :handle).from(" Example\n").to("example")
end
If the normalization accepts nil values with the ‘apply_to_nil` option, you just need to use `.from(nil).to(“Your expected value here”)`.
class User < ActiveRecord::Base
normalizes :name, with: -> name { name&.titleize || 'Untitled' },
apply_to_nil: true
end
# RSpec
RSpec.describe User, type: :model do
it { should normalize(:name).from("jane doe").to("Jane Doe") }
it { should normalize(:name).from(nil).to("Untitled") }
end
# Minitest (Shoulda)
class User < ActiveSupport::TestCase
should normalize(:name).from("jane doe").to("Jane Doe")
should normalize(:name).from(nil).to("Untitled")
end
68 69 70 71 72 73 74 |
# File 'lib/shoulda/matchers/active_record/normalize_matcher.rb', line 68 def normalize(*attributes) if attributes.empty? raise ArgumentError, 'need at least one attribute' else NormalizeMatcher.new(*attributes) end end |
#serialize(name) ⇒ SerializeMatcher
The ‘serialize` matcher tests usage of the `serialize` macro.
class Product < ActiveRecord::Base
serialize :customizations
end
# RSpec
RSpec.describe Product, type: :model do
it { should serialize(:customizations) }
end
# Minitest (Shoulda)
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()
# ...
end
end
class Product < ActiveRecord::Base
serialize :specifications, ProductSpecsSerializer
end
# RSpec
RSpec.describe Product, type: :model do
it do
should serialize(:specifications).
as(ProductSpecsSerializer)
end
end
# Minitest (Shoulda)
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()
# ...
end
end
class Product < ActiveRecord::Base
serialize :options, ProductOptionsSerializer.new
end
# RSpec
RSpec.describe Product, type: :model do
it do
should serialize(:options).
as_instance_of(ProductOptionsSerializer)
end
end
# Minitest (Shoulda)
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 |
#validate_uniqueness_of(attr) ⇒ ValidateUniquenessOfMatcher
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 instance of that model 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 :permalink, uniqueness: true
end
# RSpec
RSpec.describe Post, type: :model do
it { should validate_uniqueness_of(:permalink) }
end
# Minitest (Shoulda)
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 populate these attributes with values 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:
RSpec.describe Post, type: :model do
it { should validate_uniqueness_of(:title) }
end
However, running this test will fail with an exception such as:
Shoulda::Matchers::ActiveRecord::ValidateUniquenessOfMatcher::ExistingRecordInvalid:
validate_uniqueness_of works by matching a new record against an
existing record. If there is no existing record, it will create one
using the record you provide.
While doing this, the following error was raised:
PG::NotNullViolation: ERROR: null value in column "content" violates not-null constraint
DETAIL: Failing row contains (1, null, null).
: INSERT INTO "posts" DEFAULT VALUES RETURNING "id"
The best way to fix this is to provide the matcher with a record where
any required attributes are filled in with valid values beforehand.
(The exact error message will differ depending on which database you’re using, but you get the idea.)
This happens because ‘validate_uniqueness_of` tries to create a new post but cannot do so because of the `content` attribute: though unrelated to this test, it nevertheless needs to be filled in. As indicated at the end of the error message, the solution is to build a custom Post object ahead of time with `content` filled in:
RSpec.describe Post, type: :model do
describe "validations" do
subject { Post.new(content: "Here is the content") }
it { should validate_uniqueness_of(:title) }
end
end
Or, if you’re using [FactoryBot](github.com/thoughtbot/factory_bot) and you have a ‘post` factory defined which automatically fills in `content`, you can say:
RSpec.describe Post, type: :model do
describe "validations" do
subject { FactoryBot.build(:post) }
it { should validate_uniqueness_of(:title) }
end
end
#### Qualifiers
Use ‘on` if your validation applies only under a certain context.
class Post < ActiveRecord::Base
validates :title, uniqueness: true, on: :create
end
# RSpec
RSpec.describe Post, type: :model do
it { should validate_uniqueness_of(:title).on(:create) }
end
# Minitest (Shoulda)
class PostTest < ActiveSupport::TestCase
should validate_uniqueness_of(:title).on(:create)
end
##### with_message
Use ‘with_message` if you are using a custom validation message.
class Post < ActiveRecord::Base
validates :title, uniqueness: true, message: 'Please choose another title'
end
# RSpec
RSpec.describe Post, type: :model do
it do
should validate_uniqueness_of(:title).
('Please choose another title')
end
end
# Minitest (Shoulda)
class PostTest < ActiveSupport::TestCase
should validate_uniqueness_of(:title).
('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 :slug, uniqueness: { scope: :journal_id }
end
# RSpec
RSpec.describe Post, type: :model do
it { should validate_uniqueness_of(:slug).scoped_to(:journal_id) }
end
# Minitest (Shoulda)
class PostTest < ActiveSupport::TestCase
should validate_uniqueness_of(:slug).scoped_to(:journal_id)
end
NOTE: Support for testing uniqueness validation scoped to an array of associations is not available.
For more information, please refer to github.com/thoughtbot/shoulda-matchers/issues/814
##### 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 :key, uniqueness: { case_sensitive: false }
end
# RSpec
RSpec.describe Post, type: :model do
it { should validate_uniqueness_of(:key).case_insensitive }
end
# Minitest (Shoulda)
class PostTest < ActiveSupport::TestCase
should validate_uniqueness_of(:key).case_insensitive
end
##### ignoring_case_sensitivity
By default, ‘validate_uniqueness_of` will check that the validation is case sensitive: it asserts that uniquable attributes pass validation when their values are in a different case than corresponding attributes in the pre-existing record.
Use ‘ignoring_case_sensitivity` to skip this check. This qualifier is particularly handy if your model has somehow changed the behavior of attribute you’re testing so that it modifies the case of incoming values as they are set. For instance, perhaps you’ve overridden the writer method or added a ‘before_validation` callback to normalize the attribute.
class User < ActiveRecord::Base
validates :email, uniqueness: true
def email=(value)
super(value.downcase)
end
end
# RSpec
RSpec.describe Post, type: :model do
it do
should validate_uniqueness_of(:email).ignoring_case_sensitivity
end
end
# Minitest (Shoulda)
class PostTest < ActiveSupport::TestCase
should validate_uniqueness_of(:email).ignoring_case_sensitivity
end
##### allow_nil
Use ‘allow_nil` to assert that the attribute allows nil.
class Post < ActiveRecord::Base
validates :author_id, uniqueness: true, allow_nil: true
end
# RSpec
RSpec.describe Post, type: :model do
it { should validate_uniqueness_of(:author_id).allow_nil }
end
# Minitest (Shoulda)
class PostTest < ActiveSupport::TestCase
should validate_uniqueness_of(:author_id).allow_nil
end
##### allow_blank
Use ‘allow_blank` to assert that the attribute allows a blank value.
class Post < ActiveRecord::Base
validates :author_id, uniqueness: true, allow_blank: true
end
# RSpec
RSpec.describe Post, type: :model do
it { should validate_uniqueness_of(:author_id).allow_blank }
end
# Minitest (Shoulda)
class PostTest < ActiveSupport::TestCase
should validate_uniqueness_of(:author_id).allow_blank
end
261 262 263 |
# File 'lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb', line 261 def validate_uniqueness_of(attr) ValidateUniquenessOfMatcher.new(attr) end |