Rails 7.1 enhances PostgreSQL enum functionality
In Ruby on Rails, PostgreSQL provides an extension for defining enumerations, which allows you to specify a set of possible values for a column. This is useful when limiting your model's allowed values for a particular attribute.
Apart from creating enums, PostgreSQL supports renaming an enum and adding new and renaming enum values.
Before Rails 7.1
Before Rails 7.1, renaming an enum, adding new values to an enum or renaming enum values was possible in Rails by writing raw SQL queries.
You can rename the enum as below:
# db/migrate/20231010121212_rename_orders_current_status_enum.rb
def up
execute <<-SQL
ALTER TYPE status RENAME TO state;
SQL
end
You need to use the ALTER TYPE ... ADD VALUE
command to add new enum values.
# db/migrate/20231010121212_add_orders_current_status_enums.rb
def up
execute <<-SQL
ALTER TYPE status ADD VALUE 'archived';
ALTER TYPE status ADD VALUE 'payment_failed' BEFORE 'completed';
SQL
end
You need to use the ALTER TYPE ... RENAME VALUE
command
to rename an existing enum value.
# db/migrate/20231010121212_rename_orders_current_status_completed_enum.rb
def up
execute <<-SQL
ALTER TYPE status RENAME VALUE "completed" TO "delivered";
SQL
end
In Rails 7.1
The problem with raw SQL queries is they are harder to read and maintain than ActiveRecord queries, which follow Ruby's more natural and readable syntax. You lose the benefits of ActiveRecord's abstractions, such as automatic table aliasing and database-agnostic query generation.
Rails 7.1 adds enum rename, add value and rename value methods to extend its support for PostgreSQL enum types.
To rename an enum,
you can use the rename_enum
function as below:
# db/migrate/20231010121212_rename_orders_current_status_enum.rb
def up
rename_enum :status, to: :state
end
To add new enum values,
you need to use add_enum_value
.
# db/migrate/20231010121212_add_orders_current_status_enums.rb
def up
add_enum_value :status, "archived"
add_enum_value :status, "payment_failed", before: "completed"
end
You need to use the rename_enum_value
function to
rename an existing enum value.
# db/migrate/20231010121212_rename_orders_current_status_completed_enum.rb
def up
rename_enum_value :status, from: "completed", to: "delivered"
end
NOTE:
- The above enum support is available ONLY for the PostgreSQL database.
rename_enum
andrename_enum_value
are reversible. As per PostgreSQL limitation,add_enum_value
is not reversible since you cannot delete enum values. As an alternative, you should drop and recreate the enum entirely.
To know more about this feature, please refer to this PR.