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
endYou 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
endYou 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
endIn 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
endTo 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"
endYou 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"
endNOTE:
- The above enum support is available ONLY for the PostgreSQL database.
- rename_enumand- rename_enum_valueare reversible. As per PostgreSQL limitation,- add_enum_valueis 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.