All Versions
Latest Version
Avg Release Cycle
124 days
Latest Release
145 days ago

Changelog History
Page 2

  • v4.1.0 Changes

    July 16, 2019

    ๐Ÿ› Bug fixes

    • Fix validate_uniqueness_of so that it works when a scope is defined as a string instead of a symbol on the model. (#1176)

    • Fix have_db_index so that it can be used against multiple models that are connected to different databases. (#1200)

    ๐Ÿ”‹ Features

    • โž• Add support for Rails 6. No new Rails 6 features are supported, but only existing features that broke with the upgrade. (#1193)

    • โž• Add support for expression indexes (Rails 5, Postgres only) to have_db_index. (#1211)

    • Add allow_nil to the validate_presence_of matcher. (834d8d0, #1100)

    ๐Ÿ‘Œ Improvements

    • Update validate_presence_of so that if it is being used against an association which is required: true or optional: false, or it is not configured as such but ActiveRecord defaults belong_to associations to optional: false, and the matcher fails, the developer is reminded in the failure message that the belong_to matcher can be used instead. (#1214, 8697b01)

    • Update define_enum_for so that it produces a more helpful message on failure. (#1216)

  • v4.0.1 Changes

    February 26, 2019

    ๐Ÿ› Bug fixes

    • ๐Ÿ›  Fix gemspec so that setup script isn't installed globally when gem is installed. (#1180)
  • v4.0.0 Changes

    February 22, 2019

    ๐Ÿš€ This release mainly brings the gem up to date with modern versions of Ruby and ๐Ÿš… Rails and drops support for older, unsupported versions. The compatibility list is now:

    • ๐Ÿ’Ž Ruby: 2.6.0, 2.5.1, 2.4.4, 2.3.7
    • ๐Ÿš… Rails: 5.2.2,, 5.0.7, 4.2.10

    Backward-incompatible changes

    • โฌ‡๏ธ Drop support for Rails 4.0 and 4.1 as well as Ruby 2.0, 2.1, and 2.2, since they've been end-of-lifed. The gem now supports Ruby 2.3+ and Rails 4.2+.

    • use_before_filter, use_after_filter, and use_around_filter are no longer usable when using shoulda-matchers under Rails 5.x, as the corresponding controller callbacks don't exist there. (#1054)

    ๐Ÿ—„ Deprecations

    • define_enum_for: with is deprecated in favor of with_values. This is to prevent confusion with with_prefix and with_suffix, which are new. (#1077)

    ๐Ÿ› Bug fixes

    • ๐Ÿ›  Fix association matchers when used under Rails 5.x so that they make use of ActiveRecord::Base.connection.data_sources instead of ActiveRecord::Base.connection.tables, which was deprecated. (#933, #943, 61c3654)

    • ๐Ÿ›  Fix the serialize matcher so that it works with Rails 5.x. (#913, #965, df04f87)

    • ๐Ÿ›  Fix our custom mocking library Doublespeak, which is used by delegate_method, so that it does not produce a warning under Ruby 2.4. ([#1006], #1038, 8d7dcb8)

    • ๐Ÿ›  Fix the permit matcher so that it uses the correct method signature to call the controller action with params in order to prevent a warning under Rails 5.x. (#867, #917, #964, #989, ce9624b)

    • Fix the define_enum_for matcher so that it once more allows string columns to be used as enum attributes. (#912, #1063, 5650aae)

    • Fix validate_uniqueness_of when used under Rails 4.2 so that when the attribute you're testing is a boolean column, it will no longer emit a warning. (#949, #1073)

    • Fix validate_inclusion_of so that if it fails, it will no longer blow up with the error "undefined method `attribute_setter' for nil:NilClass". (#904)

    • โž• Add negative versions of all validation matchers (i.e. implement does_not_match? for them) to prevent them from blowing up with "undefined method `attribute_setter' for nil:NilClass". (#904)

    ๐Ÿ”‹ Features

    • Add required and optional qualifiers to belong_to and have_one matchers. (When using the belong_to matcher under Rails 5+, required is assumed unless overridden.) (#861, #870, #956, 3af3d9f)

    • Add without_validating_presence qualifier to belong_to to get around the fact that required is assumed, above. (#1153, #1154)

    • Add allow_nil qualifier to delegate_method. (#798, d49cfca)

    • Add allow_nil qualifier to validate_length_of. (#724)

    • โž• Add a port option to the route matcher to allow testing a route that has a constraint on it such that only a specific port may be used to access that route. (#954, #1074, #1075)

    • Add with_prefix and with_suffix to define_enum_for to allow testing the enum macro with corresponding prefix and suffix options (Rails 5 only). (#961, #1077)

    • Add index_errors option to has_many (Rails 5 only). (#1089, 795ca68)

    ๐Ÿ‘Œ Improvements

  • v4.0.0.rc1 Changes

    October 02, 2018

    โž• Adds support for Ruby 2.4 and 2.5 and Rails 5.x.
    โฌ‡๏ธ Drops support for Ruby 2.0 and 2.1 as well as Rails 4.0 and 4.1.

  • v3.1.3 Changes

    January 29, 2019

    ๐Ÿ‘Œ Improvements

    • โšก๏ธ Update to use BigDecimal() and avoid deprecation warnings in Ruby 2.6.
  • v3.1.2 Changes

    July 12, 2017

    ๐Ÿ—„ Deprecations

    • This is the last version that supports Rails 4.0 and 4.1 and Ruby 2.0 and 2.1.

    ๐Ÿ› Bug fixes

    • When the permit matcher was used without #on, the controller did not use params#require, the params object was duplicated, and the matcher did not recognize the #permit call inside the controller. This behavior happened because the matcher overwrote double registries with the same parameter hash whenever ActionController::Parameters was instantiated. (#899, #902, 44c019)
  • v3.1.1 Changes

    January 28, 2016

    ๐Ÿ› Bug fixes

    • ๐Ÿ‘ Some matchers make use of ActiveSupport's in? method, but do not include the file where this is defined in ActiveSupport. This causes problems with projects using shoulda-matchers that do not include all of ActiveSupport by default. To fix this, replace in? with Ruby's builtin include?. (#879)

    • validate_uniqueness_of works by creating a record if it doesn't exist, and then testing against a new record with various attributes set that are equal to (or different than) corresponding attributes in the existing record. In 3.1.0 a change was made whereby when the uniqueness matcher is given a new record and creates an existing record out of it, it ensures that the record is valid before continuing on. This created a problem because if the subject, before it was saved, was empty and therefore in an invalid state, it could not effectively be saved. While ideally this should be enforced, doing so would be a backward-incompatible change, so this behavior has been rolled back. (#880, #884, #885, 45de869)

    • Fix an issue with validate_uniqueness_of + scoped_to when used against a model where the attribute has multiple uniqueness validations and each validation has a different set of scopes. In this case, a test written for the first validation (and its scopes) would pass, but tests for the other validations (and their scopes) would not, as the matcher only considered the first set of scopes as the actual set of scopes. (#830, 28bd9a1)

    ๐Ÿ‘Œ Improvements

    • Update validate_uniqueness_of so that if an existing record fails to be created because a column is non-nullable and was not filled in, raise an ExistingRecordInvalid exception with details on how to fix the test. (78ccfc5)
  • v3.1.0 Changes

    January 11, 2016

    ๐Ÿ› Bug fixes

    • Update validate_numericality_of so that submatchers are applied lazily instead of immediately. Previously, qualifiers were order-dependent, meaning that if you used strict before you used, say, odd, then strict wouldn't actually apply to odd. Now the order that you specify qualifiers doesn't matter. (6c67a5e)

    • ๐Ÿ›  Fix allow_value so that it does not raise an AttributeChangedValueError (formerly CouldNotSetAttributeError) when used against an attribute that is an enum in an ActiveRecord model. (9e8603e)

    • Add a ignoring_interference_by_writer qualifier to all matchers, not just allow_value. This is enabled by default, which means that you should never get a CouldNotSetAttributeError again. (You may get some more information if a test fails, however.) (#786, #799, #801, #804, #817, #841, #849, #872, #873, #874, 1189934, 5532f43)

    • Fix validate_numericality_of so that it does not blow up when used against a virtual attribute defined in an ActiveRecord model (that is, an attribute that is not present in the database but is defined using attr_accessor). (#822)

    • Update validate_numericality_of so that it no longer raises an IneffectiveTestError if used against a numeric column. (#832, 5ed0362)

    ๐Ÿ”‹ Features

    • Add a new qualifier, ignoring_case_sensitivity, to validate_uniqueness_of. This provides a way to test uniqueness of an attribute whose case is normalized, either in a custom writer method for that attribute, or in a custom before_validation callback. (#836, #840)

    ๐Ÿ‘Œ Improvements

    • ๐Ÿ‘Œ Improve failure messages and descriptions of all matchers across the board so that it is easier to understand what the matcher was doing when it failed. (You'll see a huge difference in the output of the numericality and uniqueness matchers in particular.)

    • Matchers now raise an error if any attributes that the matcher is attempting to set do not exist on the model. (2962112)

    • Update validate_numericality_of so that it doesn't always run all of the submatchers, but stops on the first one that fails. Since failure messages now contain information as to what value the matcher set on the attribute when it failed, this change guarantees that the correct value will be shown. (8e24a6e)

    • Continue to detect if attributes change incoming values, but now instead of immediately seeing a CouldNotSetAttributeError, you will only be informed about it if the test you've written fails. (1189934)

    • Add an additional check to define_enum_for to ensure that the column that underlies the enum attribute you're testing is an integer column. (68dd70a)

    • Add a test for validate_numericality_of so that it officially supports money columns. (#841, a559713)

  • v3.0.1 Changes

    October 23, 2015

    ๐Ÿ› Bug fixes

    • Fix validate_inclusion_of + in_array when used against a date or datetime column/attribute so that it does not raise a CouldNotSetAttributeError. (#783, 8fa97b4)

    • Fix validate_numericality_of when used against a numeric column so that it no longer raises a CouldNotSetAttributeError if the matcher has been qualified in any way (only_integer, greater_than, odd, etc.). (#784, #812)

    ๐Ÿ‘Œ Improvements

    • validate_uniqueness_of now raises a NonCaseSwappableValueError if the value the matcher is using to test uniqueness cannot be case-swapped -- in other words, if it doesn't contain any alpha characters. When this is the case, the matcher cannot work effectively. (#789, ada9bd3)
  • v3.0.0 Changes

    October 01, 2015

    Backward-incompatible changes

    • ๐Ÿ’Ž We've dropped support for Rails 3.x, Ruby 1.9.2, and Ruby 1.9.3, and RSpec 2. All of these have been end-of-lifed. (a4045a1, b7fe87a, 32c0e62)

    • โœ… The gem no longer detects the test framework you're using or mixes itself into that framework automatically. History has shown that performing any kind of detection is prone to bugs and more complicated than it should be.

    Here are the updated instructions:

    • You no longer need to say require: false in your Gemfile; you can include the gem as normal.
    • You'll need to add the following somewhere in your rails_helper (for RSpec) or test_helper (for Minitest / Test::Unit):

      Shoulda::Matchers.configure do |config|
        config.integrate do |with|
          # Choose a test framework:
          with.test_framework :rspec
          with.test_framework :minitest
          with.test_framework :minitest_4
          with.test_framework :test_unit
          # Choose one or more libraries:
          with.library :active_record
          with.library :active_model
          with.library :action_controller
          # Or, choose the following (which implies all of the above):
          with.library :rails


    • Previously, under RSpec, all of the matchers were mixed into all of the example groups. This created a problem because some gems, such as active_model_serializers-matchers, provide matchers that share the same name as some of our own matchers. Now, matchers are only mixed into whichever example group they belong to:

      • ActiveModel and ActiveRecord matchers are available only in model example groups.
      • ActionController matchers are available only in controller example groups.
      • The route matcher is available only in routing example groups.

    (af98a23, 8cf449b)

    • There are two changes to allow_value:

      • The negative form of allow_value has been changed so that instead of asserting that any of the given values is an invalid value (allowing good values to pass through), assert that all values are invalid values (allowing good values not to pass through). This means that this test which formerly passed will now fail:
      expect(record).not_to allow_value('good value', *bad_values)


      • allow_value now raises a CouldNotSetAttributeError if in setting the attribute, the value of the attribute from reading the attribute back is different from the one used to set it.

      This would happen if the writer method for that attribute has custom logic to ignore certain incoming values or change them in any way. Here are three examples we've seen:

      • You're attempting to assert that an attribute should not allow nil, yet the attribute's writer method contains a conditional to do nothing if the attribute is set to nil:
        class Foo
          include ActiveModel::Model
          attr_reader :bar
          def bar=(value)
            return if value.nil?
            @bar = value
        describe Foo do
          it do
            foo =
   = "baz"
            # This will raise a CouldNotSetAttributeError since `` is now "123"
            expect(foo).not_to allow_value(nil).for(:bar)
      • You're attempting to assert that an numeric attribute should not allow a string that contains non-numeric characters, yet the writer method for that attribute strips out non-numeric characters:
        class Foo
          include ActiveModel::Model
          attr_reader :bar
          def bar=(value)
            @bar = value.gsub(/\D+/, '')
        describe Foo do
          it do
            foo =
            # This will raise a CouldNotSetAttributeError since `` is now "123"
            expect(foo).not_to allow_value("abc123").for(:bar)
      • You're passing a value to allow_value that the model typecasts into another value:
        describe Foo do
          # Assume that `attr` is a string
          # This will raise a CouldNotSetAttributeError since `attr` typecasts `[]` to `"[]"`
          it { should_not allow_value([]).for(:attr) }

      With all of these failing examples, why are we making this change? We want to guard you (as the developer) from writing a test that you think acts one way but actually acts a different way, as this could lead to a confusing false positive or negative.

      If you understand the problem and wish to override this behavior so that you do not get a CouldNotSetAttributeError, you can add the ignoring_interference_by_writer qualifier like so. Note that this will not always cause the test to pass.

      it { should_not allow_value([]).for(:attr).ignoring_interference_by_writer }


    • validate_uniqueness_of is now properly case-sensitive by default, to match the default behavior of the validation itself. This is a backward-incompatible change because this test which incorrectly passed before will now fail:

      class Product < ActiveRecord::Base
        validates_uniqueness_of :name, case_sensitive: false
      describe Product do
        it { validate_uniqueness_of(:name) }


    • ensure_inclusion_of, ensure_exclusion_of, and ensure_length_of have been removed in favor of their validate_* counterparts. (55c8d09)

    • set_the_flash and set_session have been changed to more closely align with each other:

      • set_the_flash has been removed in favor of set_flash. (801f2c7)
      • set_session('foo') is no longer valid syntax, please use set_session['foo'] instead. (535fe05)
      • set_session['key'].to(nil) will no longer pass when the key in question has not been set yet. (535fe05)
    • Change set_flash so that set_flash[:foo].now is no longer valid syntax. You'll want to use[:foo] instead. This was changed in order to more closely align with how works when used in a controller. (#755, #752)

    • Change behavior of validate_uniqueness_of when the matcher is not qualified with any scopes, but your validation is. Previously the following test would pass when it now fails:

      class Post < ActiveRecord::Base
        validate :slug, uniqueness: { scope: :user_id }
      describe Post do
        it { should validate_uniqueness_of(:slug) }


    ๐Ÿ› Bug fixes

    • โœ… So far the tests for the gem have been running against only SQLite. Now they run against PostgreSQL, too. As a result we were able to fix some Postgres-related bugs, specifically around validate_uniqueness_of:

      • When scoped to a UUID column that ends in an "f", the matcher is able to generate a proper "next" value without erroring. (#402, #587, #662)
      • Support scopes that are PostgreSQL array columns. Please note that this is only supported for Rails 4.2 and greater, as versions before this cannot handle array columns correctly, particularly in conjunction with the uniqueness validator. (#554)
      • Fix so that when scoped to a text column and the scope is set to nil before running it through the matcher, the matcher does not fail. (#521, #607)
    • Fix define_enum_for so that it actually tests that the attribute is present in the list of defined enums, as you could fool it by merely defining a class method that was the pluralized version of the attribute name. In the same vein, passing a pluralized version of the attribute name to define_enum_for would erroneously pass, and now it fails. (#641)

    • ๐Ÿ›  Fix permit so that it does not break the functionality of ActionController::Parameters#require. (#648, #675)

    • Fix validate_uniqueness_of + scoped_to so that it does not raise an error if a record exists where the scoped attribute is nil. (#677)

    • ๐Ÿ›  Fix route matcher so if your route includes a default format, you can specify this as a symbol or string. (#693)

    • Fix validate_uniqueness_of so that it allows you to test against scoped attributes that are boolean columns. (#457, #694)

    • Fix failure message for validate_numericality_of as it sometimes didn't provide the reason for failure. (#699)

    • ๐Ÿ›  Fix shoulda/matchers/independent so that it can be required independently, without having to require all of the gem. (#746, e0a0200)

    ๐Ÿ”‹ Features

    • โž• Add on qualifier to permit. This allows you to make an assertion that a restriction was placed on a slice of the params hash and not the entire params hash. Although we don't require you to use this qualifier, we do recommend it, as it's a more precise check. (#675)

    • Add strict qualifier to validate_numericality_of. (#620)

    • Add on qualifier to validate_numericality_of. (9748869; h/t #356, #358)

    • Add join_table qualifier to have_and_belong_to_many. (#556)

    • allow_values is now an alias for allow_value. This makes more sense when checking against multiple values:

      it { should allow_values('this', 'and', 'that') }