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?
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