Rails 7.1 enhances PostgreSQL enum functionality

railsAugust 02, 2023Dotby Alkesh Ghorpade

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:

  1. The above enum support is available ONLY for the PostgreSQL database.
  2. rename_enum and rename_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.

Closing Remark

Could your team use some help with topics like this and others covered by ShakaCode's blog and open source? We specialize in optimizing Rails applications, especially those with advanced JavaScript frontends, like React. We can also help you optimize your CI processes with lower costs and faster, more reliable tests. Scraping web data and lowering infrastructure costs are two other areas of specialization. Feel free to reach out to ShakaCode's CEO, Justin Gordon, at justin@shakacode.com or schedule an appointment to discuss how ShakaCode can help your project!
Are you looking for a software development partner who can
develop modern, high-performance web apps and sites?
See what we've doneArrow right