Search code examples
ruby-on-railsrspecshoulda

Rspec - Uniqueness shouldamatcher failing


I have an ActiveRecord table with a column called name. I need this field to be present and unique. So I have the following specs

it { should validate_presence_of(:name) }
it { should validate_uniqueness_of(:name) }

And the corresponding rule in the model is:

validates :name, presence: true, uniqueness: true

My factory contains the following:

FactoryBot.define do
  factory :model_name do
    sequence(:name) { |n| "Name #{n}" }

    after(:build) do |model|
      pack.rels << build(:relation)
    end
  end
end

The problem is that when I run the specs I get the following error.

Failure/Error: it { should validate_uniqueness_of(:name) }
     
     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
    Mysql2::Error: Field 'name' doesn't have a default value: INSERT INTO `table_name`

What am I doing wrong?


Solution

  • The validate_uniqueness_of matcher behaves differently in comparison to other matches because it creates an instance for the model if one doesn't exist yet. There is a Caveat section on the documentation detailing the scenario described in your question.

    To solve this, you want to create an object with pre-populated fields within the scope of your tests, so you have control over the attribute values used during the execution.

    Since you're using FactoryBot, you could do the following:

    RSpec.describe ModelName, type: :model do
      describe "validations" do
        subject { FactoryBot.build(:model_name) }
        it { should validate_presence_of(:name) }
        it { should validate_uniqueness_of(:name) }
      end
    end