degenPenguin
degenPenguin

Reputation: 725

Enumerated Types with ActiveRecord and Postgresql

I am following this tutorial from SitePoint to set a model property to an Enum value, which is supported by Rails as of 4.1.

Instead of Gender Enum, I am trying to add a Season Enum.

This is the issue I get in my schema.db

# Could not dump table "semesters" because of following StandardError
#   Unknown type 'season' for column 'season'

This is my migration:

class AddSeasonToSemesters < ActiveRecord::Migration[5.1]
  def up
    execute <<-SQL
    CREATE TYPE season AS ENUM ('fall', 'winter', 'spring', 'summer');
    SQL

    add_column :semesters, :season, :season, index: true
  end

  def down
    remove_column :semesters, :season

    execute <<-SQL
    DROP TYPE season;
    SQL
  end
end

And my model file:

class Semester < ApplicationRecord
  enum season: {
      fall: 'fall',
      winter: 'winter',
      spring: 'spring',
      summer: 'summer'
  }
end

Any idea what I am doing wrong? Any direction would be appreciated, thank you.

Upvotes: 3

Views: 962

Answers (1)

mu is too short
mu is too short

Reputation: 434665

You need to switch from db/schema.rb to db/structure.sql.

The underlying problem is that schema.rb is a representation of the database's structure as ActiveRecord sees it but ActiveRecord doesn't understand a lot of things (such as create type, CHECK constraints, and other things that show up in execute some_raw_sql statements in migrations) that PostgreSQL does. You can create type all you want but schema.rb will never see it.

If you want to use things that ActiveRecord doesn't understand then you have to use db/structure.sql to store your database's structure. structure.sql stores the database's structure as the database understands it, not as ActiveRecord understands it.

Switching is easy:

  1. Update your config/application.rb to contain config.active_record.schema_format = :sql.
  2. Do a rake db:structure:dump to get an initial db/structure.sql.
  3. Delete db/schema.rb from your directory tree and revision control.
  4. Add db/structure.sql to revision control.
  5. Adjust your rake habits:
    • Use db:structure:dump instead of db:schema:dump
    • Use db:structure:load instead of db:schema:load

That said, I'm not sure how well PostgreSQL's native enum types will interact with ActiveRecord as I've never done it. AR's enums are a client-side translation between strings and integers but PostgreSQL's enums are handled inside the database and they don't know about each other. There might be conflicts and you will need to be sure to keep them synchronized with each other.

Upvotes: 5

Related Questions