Rails 7 added support for custom enum types in PostgreSQL with introduction of create_enum to add a new enum type and t.enum to add a column.
Rails 7.1 has extended the ability to rename an enum, add enum value and rename enum value for the Postgres database adapter.
The add_enum_value
method provides a straightforward way to add new values to a PostgreSQL enum type without needing to execute raw SQL.
class AddEnumToArticles < ActiveRecord::Migration[7.2]
def change
create_enum :status, ["draft", "published", "archived", "trashed"]
safety_assured do
change_table :articles do |t|
t.enum :current_status, enum_type: "status", default: "draft", null: false
end
end
end
end
class AddReviewToArticleStatus < ActiveRecord::Migration[7.2]
def change
add_enum_value :status, 'review'
end
end
Before
When we use add_enum_value
, PostgreSQL checks for duplicates
and raises a PG::DuplicateObject
error if a value already exists. ActiveRecord captures this as ActiveRecord::StatementInvalid
when trying to add a duplicate value.
class AddReviewToArticleStatus < ActiveRecord::Migration[7.2]
def change
add_enum_value :status, 'review'
end
end
PG::DuplicateObject: ERROR: enum label "review" already exists
ActiveRecord::StatementInvalid: PG::DuplicateObject: ERROR: enum label "review" already exists (ActiveRecord::StatementInvalid)
To avoid the adding of dubplicate enums, we can use PostgreSQL IF NOT EXISTS
but it only works with raw SQL. So we can not use it with add_enum_value
.
After
Rails 8 adds support for PostgreSQL IF NOT EXISTS
functionality with the introduction of if_not_exists option on the add_enum_value method.
With this if_not_exists
option, we can now safely add a new enum value, preventing errors if the value already exists.
class AddReviewToArticleStatus < ActiveRecord::Migration[8.0]
def change
add_enum_value :status, 'review', if_not_exists: true
end
end
If the enum doesn’t exist then the above migration will add the enum otherwise it won’t raise an error.