bibendi / activerecord-postgres_enum

Integrate PostgreSQL's enum data type into ActiveRecord's schema and migrations.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

db:setup fails with ActiveRecord::StatementInvalid: PG::DuplicateObject

emersonthis opened this issue · comments

Describe the bug
After adding a couple migrations that use add_enum I can no longer run rake db:setup without the following error:

$ bundle exec rake db:setup
Database 'myapp_dev' already exists
Database 'myapp_test' already exists
rake aborted!
ActiveRecord::StatementInvalid: PG::DuplicateObject: ERROR:  type "question_answer_length" already exists
/Users/emerson/Code/myapp/db/schema.rb:18:in `block in <main>'
/Users/emerson/Code/myapp/db/schema.rb:13:in `<main>'
/Users/emerson/.rbenv/versions/2.6.3/bin/bundle:23:in `load'
/Users/emerson/.rbenv/versions/2.6.3/bin/bundle:23:in `<main>'

Caused by:
PG::DuplicateObject: ERROR:  type "question_answer_length" already exists
/Users/emerson/Code/myapp/db/schema.rb:18:in `block in <main>'
/Users/emerson/Code/myapp/db/schema.rb:13:in `<main>'
/Users/emerson/.rbenv/versions/2.6.3/bin/bundle:23:in `load'
/Users/emerson/.rbenv/versions/2.6.3/bin/bundle:23:in `<main>'
Tasks: TOP => db:schema:load
(See full trace by running task with --trace)

To Reproduce
Steps to reproduce the behavior:

  1. Added gem 'activerecord-postgres_enum' to Gemfile
  2. $ bundle install
  3. Create a couple migrations that use add_enum
  4. Run $ bundle exec rake db:setup

Expected behavior
Command runs without error.

Context (please complete the following information):

  • OS: MacOS
  • Version 10.15.3

Additional context
Ruby version 2.6.3p62
PostgreSQL version 12

I also tried running db:reset first. The same error occurs.

It doesn't look like it is happened because of this gem. Please provide a bare minimum application that is representing that bug.

@bibendi I'm seeing the same thing and it happens with any Rails app I've tried that uses the Ruby DSL for the schema.

The problem appears to be that create_enum doesn't have a corresponding :force option like create_table does. So, create_enum unconditionally tries to create the enum when processing schema.rb, without dropping the old enum first. If you don't drop the database after you've run your migrations and then run db:setup, the create_enum call will conflict with the existing enum.

Adding on, there is support in schema.rb for a :if_not_exists keyword option, like so:

create_enum :integration_account_state, [
  "connected",
  "errored",
  "pending",
], if_not_exists: true

This option isn't documented and isn't set by default, which is in contrast to how ActiveRecord handles create_table. I'd suggest that there should be a :force option as well because :if_not_exists won't handle the case where the enum variants change. If they change and you run db:setup, you'll end up with the old values.

@nirvdrum, I agree with you. It looks like it needs to be implemented force: :cascade option and enable it by default in the schema.