-
-
Notifications
You must be signed in to change notification settings - Fork 16
Enum
Enum type manager. For each enum-type created on the database, it allows 2 behaviors: Single enum attribution, Array (Set-like) attribution. For Array attribution check the link. It creates a separated class to hold each enum set that can be used by multiple models, it also keeps the database consistent. The enum type is known to have a better performance against string- and integer-like enums. PostgreSQL Docs
First, you have to create the enum during your migration, since it's the database that holds the list of possible values.
create_enum :roles, %i(visitor manager admin)Some other examples are:
# Only for Rails < 7.0
# ['status_foo', 'status_bar']
create_enum :status, %i(foo bar), prefix: true
# 'foo_tst', 'bar_tst']
create_enum :status, %i(foo bar), suffix: 'tst'NOTE: The
create_enummethod now exists on Rails, so it was removed from the gem, preventing the use of prefix and suffix. However, theadd_enum_valuesstill exists only in this gem.
You can also manage this type along other migrations, renaming, adding values, or deleting it.
# Rename enum by renaming the type it represents
rename_type :status, :content_status
# Adding values
add_enum_values :status, %i(baz qux) # To the end of the list
add_enum_values :status, %i(baz qux), prepend: true # At the beginning of the list
add_enum_values :status, %i(baz qux), after: 'foo' # After a certain value
add_enum_values :status, %i(baz qux), before: 'foo' # Before a certain value
add_enum_values :status, %i(baz qux), prefix: true # With type name as prefix
add_enum_values :status, %i(baz qux), suffix: 'tst' # With a specific suffix
# Deleting an enum by dropping the type it represents
drop_type :statusOnce you've created the type, you can use it while creating your table in three ways
create_table :users do |t|
t.string :name
t.role :role # Uses the type of the column, since enum is a type
t.enum :status # Figures the type name from the column name !! ONLY RAILS < 7.0
t.enum :last_status, subtype: :status # Explicit tells the type to be used !! ONLY RAILS < 7.0
t.enum :last_status, enum_type: :status # This is the official Rails 7.0 syntax !! ONLY RAILS >= 7.0
endSometimes, adding values are prevented because migrations run inside of transactions, but there are some occasions that PostgreSQL doesn't allow that, check PostgreSQL Docs. In those cases, just add disable_ddl_transaction! to the migration:
class AddEnumValue < ActiveRecord::Migration[5.2]
disable_ddl_transaction!
def up
add_enum_values :status, %i(baz qux), after: :foo
end
def down
# this migration is irreversible
end
endEach enum type loaded from the database will have its own class type of value, created under the enum.namespace namespace.
Enum::Roles
# You can get a representative value from there
Enum::Roles.admin
# Or you can get the list of values
Enum::Roles.values
# You can also get all the values as symbols
Enum::Roles.keys
# Allows you to iterate over the values directly from the class
Enum::Roles.each do |role|
puts role
end
# You can use index-based references of a value
Enum::Roles.new(0) # :visitor
Enum::Roles.admin.to_i # 2You have to go to each of your models and enable the functionality for each enum-type field. You don't need to provide the values since they will be loaded from the database. The method name is defined on enum.base_method.
# models/user.rb
class User < ActiveRecord::Base
torque_enum :role, :status
endYou are able to access the list of values trough the class that holds the enum:
User.roles # List of strings
User.roles_keys # List of symbolsYou can set the column value from String, Symbol, and Integer:
user = User.new
user.role = 'admin' # :admin
user.role = :manager # :manager
user.role = 0 # :visitorThis allows you to compare values, or make questions about it:
other_user = User.new(role: :manager)
user = User.new(role: :manager)
user.role > :admin # false
user.role == 1 # true
user.role >= other_user.role # true
user.role.manager? # true
user.visitor? # falseThe bang! methods are controlled by the enum.save_on_bang:
# The following will only perform a save on the database if enum.save_on_bang is set to true
user = User.new(role: :manager)
user.admin!You can reach the I18n translations from three different ways, and the scopes are configured on enum.i18n_scopes. On the third one, only the scopes on enum.i18n_type_scope are used, that allows per-model customization.
user = User.new(role: :manager)
user.role.text # User's manager
user.role_text # User's manager
Enum::Roles.manager.text # ManagerFor each value, the model where the enum was defined receives additional scopes, making it easy to filter records.
User.manager # SELECT * FROM "users" WHERE "users"."role" = 'manager'When testing models or creating records using factories, Enum provides an easy way to get a random value from the list of any enum types. Besides the normal User.roles.sample, you can also use:
Enum.sample(:roles)Can't find what you're looking for? Add an issue to the issue tracker.