Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Seeded database key values conflicting with factory bot create/build

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.

document_type factory

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

attempted fixes

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!

like image 582
thornomad Avatar asked Oct 23 '25 16:10

thornomad


2 Answers

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
like image 52
Sovalina Avatar answered Oct 26 '25 08:10

Sovalina


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}))")
like image 41
Shane Avatar answered Oct 26 '25 06:10

Shane



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!