PostgreSQL provides in-built support for enumerated types that Rails can then take advantage of. However, it is often a pain to make use of this feature since it’s tedious to create custom enum types in PostgreSQL via ActiveRecord migrations.
Before
The previous method of creating custom enum types is done by executing direct SQL statements.
# db/migrate/*_create_articles.rb
def up
execute <<-SQL
CREATE TYPE status AS ENUM ('draft', 'published', 'archived', 'trashed');
SQL
create_table :articles do |t|
t.column :current_status, :status
end
end
Arguably this is not convenient in reality!
After
Often many Rails + PostgreSQL developers use structure.sql
instead of schema.rb
to make it easier to manage custom
enum types.
Fortunately,
Rails 7 adds support for custom enum types in PostgreSQL.
This change removes that friction by introducing create_enum
to add a new enum type
and t.enum
to add a column.
Enum types work well with
ActiveRecord::Enum
and
now it’s easier than ever to utilize them.
def up
# note that enums cannot be dropped
create_enum :status, ["draft", "published", "archived", "trashed"]
change_table :articles do |t|
t.enum :current_status, enum_type: "status", default: "draft", null: false
end
end
The enum definitions and enum columns get added to the schema.rb, so we can load them into a test database, and they’ll work correctly.
ActiveRecord::Schema.define(version: 2022_01_03_113555) do
# These are the extensions that must be enabled to support this database.
enable_extension "plpgsql"
# Custom types defined in this database.
# Note that some types may not work with other database engines. Be careful if changing the database.
create_enum "status", ["draft", "published", "archived", "trashed"]
create_table "articles", force: :cascade do |t|
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.enum "current_status", default: "draft", null: false, enum_type: "status"
end
end
It is important to note that this is not compatible with any other database adapters. So if one decides to change the database at any point in the future, this would have to be a manual migration.