Enummer

Gem Codecov Licence Documentation

Enummer is a lightweight answer for adding enums with multiple values to Rails, with a similar syntax to Rails' built-in enum.

Enummer officially supports Ruby versions 2.7, 3.0 and 3.1 with SQLite, PostgreSQL, and MariaDB.

Installation

Add gem "enummer" to your Gemfile and bundle.

Usage

Setup

Create a migration for an integer that looks something like this:

class CreateUsers < ActiveRecord::Migration[7.0]
  def change
    create_table :users do |t|
      t.integer :permissions, default: 0, null: false
    end
  end
end

Now set up enummer with the available values in your model:

enummer permissions: %i[read write execute]

Similar to enum, enummer can also be initialized with a hash, where the numeric index represents the position of the bit that maps to the flag:

enummer permissions: {
  read: 0,
  write: 1,
  execute: 2
}

This makes it easier to add/remove entries without worrying about migrating historical data.

Scopes

Scopes will now be provided for <option> and not_<option>.

User.read
User.not_read
User.write
User.not_write
User.execute
User.not_execute

Additionally, a with_<name> scope will be generated which returns all records that match all given options. E.g.:

user1 = User.create!(permissions: %i[read write execute])
user2 = User.create!(permissions: %i[read write])
user3 = User.create!(permissions: %i[read])

# .where(permissions: ...) will generate an `IN` query, returning all records that have *any*
# of those permissions.
User.where(permissions: %i[read write]) # => [user1, user2, user3]

# .with_permissions will return only users that have at least all of the given set of permissions
User.with_permissions(%i[read write]) # => [user1, user2]

Getter methods

Simply calling the instance method for the column will return an array of options. Question mark methods are also provided.

user = User.last

user.permissions # => [:read, :write]

user.read? # => true
user.write? # => true
user.execute? # => false

Setter methods

Options can be set with an array of symbols or via bang methods. Bang methods will additionally persist the changes.

user.update(permissions: %i[read write])
user.write!

FAQ

Which data type should I use?

That depends on how many options you expect to store. In PostgreSQL you should be able to store bytes * 8 - 1 of your data type:

Type Bytes Values
smallint 2 15
integer 4 31
bigint 8 65
numeric ??? all of them

How can I use it outside of Rails?

lol stop

Contributing

Make an issue / PR and we'll see.

Development

$ cd enummer
$ bundle install
$ cd test/dummy
$ RAILS_ENV=test DATABASE_URL=sqlite3:dummy_test rails db:setup
$ cd ../..
$ RAILS_ENV=test DATABASE_URL=sqlite3:dummy_test bin/test

Alternatives

License

The gem is available as open source under the terms of the MIT License.