bibendi / activerecord-postgres_enum

Integrate PostgreSQL's enum data type into ActiveRecord's schema and migrations.
MIT License
361 stars 24 forks source link

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

Closed emersonthis closed 4 years ago

emersonthis commented 4 years ago

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):

Additional context Ruby version 2.6.3p62 PostgreSQL version 12

emersonthis commented 4 years ago

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

bibendi commented 4 years ago

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

emersonthis commented 4 years ago

I’ll work on preparing that...

Another detail I forgot to include: before installing this gem my migrations created the enum types with raw sql queries. I retroactively replaced them with create create_enum which seemed to work fine as far as generating a proper schema file. But maybe there’s some kind of conflict with the previous implementation

On Jun 20, 2020, at 5:15 AM, Misha Merkushin notifications@github.com wrote:

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

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or unsubscribe.

nirvdrum commented 4 years ago

@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.

nirvdrum commented 4 years ago

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.

bibendi commented 4 years ago

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