Reputation: 6797
Our rails database is pre-seeded with some data for a few of our static models. For example, we have a DocumentType
model that gets populated/updated through db/seeds.rb
. Users can't modify this model.
This doesn't seem to play nicely with factory_bot, however; when I try to :
create(:document_type)
I get an error stating:
ActiveRecord::RecordNotUnique: PG::UniqueViolation: ERROR: duplicate key value violates unique constraint "document_types_pkey" DETAIL: Key (id)=(1) already exists.
Every time I run the test, this error occurs but the key (id) that is attempted to be save increments. Then, eventually, the test passes when it's outside the range of the seeded data.
What I don't understand is why factory_bot is actually setting the id
value and not letting the database assign it when the record is saved.
FactoryBot.define do
factory :document_type do
label 'Alien Spacecraft License'
description 'It should be obvious, I think'
created_at { Time.now - 30.days }
updated_at { Time.now - 30.days }
end
end
What I have tried is creating a fixture file that imitates exactly what is in the seeds.rb file -- when I do this, factory_bot honors the id
values set in the fixture. But it causes a lot of duplicate efforts (I have to keep the seeds in sync with the fixtures).
I have looked at using the fixtures to populate the database but, unfortunately in our case, we are using hard-coded IDs in the seed data to insert/update ... so fixtures don't seem like a good seeding option.
Am curious if anyone has any ideas. Thanks!
Upvotes: 4
Views: 1274
Reputation: 1075
In my case, this assumption is wrong:
What I don't understand is why factory_bot is actually setting the id value and not letting the database assign it when the record is saved.
FactoryBot is not setting the ID. It's the database's autoincrement which is wrong. By setting IDs by hand, the autoincrement value is not increased alongside it. So, it's still set to 1
even though you've used up that value.
To this fix, after loading my fixtures, I manually recalculated the sequence number:
ActiveRecord::Base.connection.execute("SELECT setval('#{klass.sequence_name}', (SELECT MAX(id) FROM #{klass.table_name}))")
Upvotes: 2
Reputation: 5609
Maybe try to sequence your document_type
factory id to start increment after the last id of your seed
FactoryBot.define do
factory :document_type do
sequence(:id) {|n| n + 30 } #i.e n + last id known in seed
end
end
Upvotes: 4