1

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?

5
  • 2
    Please add your test -- this looks like an issue with your set up Commented Dec 12, 2024 at 15:19
  • I added where exactly I got the error, in which test I mean. Also added the factory Commented Dec 15, 2024 at 12:48
  • 1
    Your factory seems wrong - it’s not setting the name value in the table. Hard to tell where you have an error since everything in your examples has generic names. Commented Dec 15, 2024 at 16:55
  • 1
    Did you set subject in your test? e.g. subject {FactoryBot.build(:model_name)}? Commented Dec 23, 2024 at 20:41
  • This looks to be a problem that could be fixed by adding a database migration to set a default value to null or empty on the db level. Post your schema and migrations for this model Commented Dec 23, 2024 at 21:02

1 Answer 1

1

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
Sign up to request clarification or add additional context in comments.

1 Comment

Perfect. Thanks for pointing this out from the documentation

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.