Enummer
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
- flag_shih_tzu
- Lots of booleans
- DB Arrays
License
The gem is available as open source under the terms of the MIT License.