Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/brainspec/enumerize
Enumerated attributes with I18n and ActiveRecord/Mongoid support
https://github.com/brainspec/enumerize
activerecord mongoid ruby
Last synced: about 2 months ago
JSON representation
Enumerated attributes with I18n and ActiveRecord/Mongoid support
- Host: GitHub
- URL: https://github.com/brainspec/enumerize
- Owner: brainspec
- License: mit
- Created: 2012-01-25T10:31:04.000Z (almost 13 years ago)
- Default Branch: master
- Last Pushed: 2024-03-25T17:28:15.000Z (9 months ago)
- Last Synced: 2024-03-25T21:15:03.664Z (9 months ago)
- Topics: activerecord, mongoid, ruby
- Language: Ruby
- Homepage:
- Size: 650 KB
- Stars: 1,711
- Watchers: 35
- Forks: 190
- Open Issues: 3
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: MIT-LICENSE
Awesome Lists containing this project
- awesome-ruby-toolbox - enumerize - Enumerated attributes with I18n and ActiveRecord/Mongoid/MongoMapper support (Active Record Plugins / Active Record Enumerations)
- awesome-ruby - Enumerize - Enumerated attributes with I18n and ActiveRecord/Mongoid/MongoMapper support. (ORM/ODM Extensions)
- awesome-rails-gem - Enumerize - Enumerated attributes with I18n and ActiveRecord/Mongoid support. It can be integrated with Simple Form. (Active Record / Omniauth)
README
# Enumerize [![Ruby](https://github.com/brainspec/enumerize/actions/workflows/ruby.yml/badge.svg)](https://github.com/brainspec/enumerize/actions/workflows/ruby.yml)
Enumerated attributes with I18n and ActiveRecord/Mongoid/MongoMapper/Sequel support
## Table of Contents
- [Installation](#installation)
- [Supported Versions](#supported-versions)
- [Usage](#usage)
- [Database support](#database-support)
- [ActiveRecord](#activerecord)
- [Mongoid](#mongoid)
- [MongoMapper](#mongomapper)
- [I18n Support](#i18n-support)
- [I18n Helper Methods](#i18n-helper-methods)
- [Boolean Helper Methods](#boolean-helper-methods)
- [Basic](#basic)
- [Predicate Methods](#predicate-methods)
- [Optimzations and Tips](#optimzations-and-tips)
- [Extendable Module](#extendable-module)
- [Customizing Enumerize Value](#customizing-enumerize-value)
- [ActiveRecord scopes](#activerecord-scopes)
- [Array-like Attributes](#array-like-attributes)
- [Forms](#forms)
- [SimpleForm](#simpleform)
- [Formtastic](#formtastic)
- [Testing](#testing)
- [RSpec](#rspec)
- [Minitest with Shoulda](#minitest-with-shoulda)
- [Other Integrations](#other-integrations)
- [Contributing](#contributing)## Installation
Add this line to your application's Gemfile:
gem 'enumerize'
And then execute:
$ bundle
Or install it yourself as:
$ gem install enumerize
## Supported Versions
- Ruby 3.0+
- Rails 6.1+## Usage
Basic:
```ruby
class User
extend Enumerizeenumerize :role, in: [:user, :admin]
end
```Note that enumerized values are just identifiers so if you want to use multi-word, etc. values then you should use `I18n` feature.
---
## Database support
### ActiveRecord
```ruby
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :status
t.string :rolet.timestamps
end
end
endclass User < ActiveRecord::Base
extend Enumerizeenumerize :status, in: [:student, :employed, :retired], default: lambda { |user| StatusIdentifier.status_for_age(user.age).to_sym }
enumerize :role, in: [:user, :admin], default: :user
end
```:warning: By default, `enumerize` adds `inclusion` validation to the model. You can skip validations by passing `skip_validations` option. :warning:
```ruby
class User < ActiveRecord::Base
extend Enumerizeenumerize :status, in: [:student, :employed, :retired], skip_validations: lambda { |user| user.new_record? }
enumerize :role, in: [:user, :admin], skip_validations: true
end
```### Mongoid
```ruby
class User
include Mongoid::Document
extend Enumerizefield :role
enumerize :role, in: [:user, :admin], default: :user
end
```### MongoMapper
```ruby
class User
include MongoMapper::Document
extend Enumerizekey :role
enumerize :role, in: [:user, :admin], default: :user
end
```---
## I18n Support
```ruby
en:
enumerize:
user:
status:
student: "Student"
employed: "Employed"
retired: "Retiree"
```or if you use `status` attribute across several models you can use `defaults` scope:
```ruby
en:
enumerize:
defaults:
status:
student: "Student"
employed: "Employed"
retired: "Retiree"
```You can also pass `i18n_scope` option to specify scope (or array of scopes) storing the translations.
```ruby
class Person
extend Enumerize
extend ActiveModel::Namingenumerize :status, in: %w[student employed retired], i18n_scope: "status"
enumerize :roles, in: %w[user admin], i18n_scope: ["user.roles", "roles"]
enumerize :color, in: %w[green blue], i18n_scope: proc { |value| "color" }
end# localization file
en:
status:
student: "Student"
employed: "Employed"
retired: "Retiree"
user:
roles:
user: "User"
roles:
admin: "Admin"
```Note that if you want to use I18n feature with plain Ruby object don't forget to extend it with `ActiveModel::Naming`:
```ruby
class User
extend Enumerize
extend ActiveModel::Naming
end
```### I18n Helper Methods
#### \*\_text / .text
Attribute's I18n text value:
```ruby
@user.status_text # or @user.status.text
```#### values
List of possible values for an enumerized attribute:
```ruby
User.status.values # or User.enumerized_attributes[:status].values
# => ['student', 'employed', 'retired']
```#### I18n text values
List of possible I18n text values for an enumerized attribute:
```ruby
User.status.values.collect(&:text)
# => ['Student', 'Employed', 'Retiree']
```#### Form example
Use it with forms (it supports `:only` and `:except` options):
```erb
<%= form_for @user do |f| %>
<%= f.select :status, User.status.options %>
<% end %>
```---
## Boolean Helper Methods
### Basic
```ruby
user.status = :student
user.status.student? #=> true
user.status.retired? #=> false
```### Predicate Methods
```ruby
class User
extend Enumerizeenumerize :status, in: %w(student employed retired), predicates: true
enduser = User.new
user.student? # => false
user.employed? # => falseuser.status = :student
user.student? # => true
user.employed? # => false
```:warning: If `enumerize` is used with Mongoid, it's not recommended to use `"writer"` as a field value since `writer?` is defined by Mongoid. [See more](https://github.com/brainspec/enumerize/issues/235). :warning:
#### Predicate Prefixes
```ruby
class User
extend Enumerizeenumerize :status, in: %w(student employed retired), predicates: { prefix: true }
enduser = User.new
user.status = 'student'
user.status_student? # => true
```Use `:only` and `:except` options to specify what values create predicate methods for.
---
## Optimzations and Tips
### Extendable Module
To make some attributes shared across different classes it's possible to define them in a separate module and then include it into classes:
```ruby
module RoleEnumerations
extend Enumerizeenumerize :roles, in: %w[user admin]
endclass Buyer
include RoleEnumerations
endclass Seller
include RoleEnumerations
end
```### Customizing Enumerize Value
It's also possible to store enumerized attribute value using custom values (e.g. integers). You can pass a hash as `:in` option to achieve this:
```ruby
class User < ActiveRecord::Base
extend Enumerizeenumerize :role, in: { user: 1, admin: 2 }
enduser = User.new
user.role = :user
user.role #=> 'user'
user.role_value #=> 1User.role.find_value(:user).value #=> 1
User.role.find_value(:admin).value #=> 2
```### ActiveRecord scopes:
#### Basic
```ruby
class User < ActiveRecord::Base
extend Enumerize
enumerize :role, in: [:user, :admin], scope: true
enumerize :status, in: { student: 1, employed: 2, retired: 3 }, scope: :having_status
endUser.with_role(:admin)
# SELECT "users".* FROM "users" WHERE "users"."role" IN ('admin')User.without_role(:admin)
# SELECT "users".* FROM "users" WHERE "users"."role" NOT IN ('admin')User.having_status(:employed).with_role(:user, :admin)
# SELECT "users".* FROM "users" WHERE "users"."status" IN (2) AND "users"."role" IN ('user', 'admin')
```#### Shallow Scopes
Adds named scopes to the class directly.
```ruby
class User < ActiveRecord::Base
extend Enumerize
enumerize :status, in: [:student, :employed, :retired], scope: :shallow
enumerize :role, in: { user: 1, admin: 2 }, scope: :shallow
endUser.student
# SELECT "users".* FROM "users" WHERE "users"."status" = 'student'User.admin
# SELECT "users".* FROM "users" WHERE "users"."role" = 2
```:warning: It is not possible to define a scope when using the `:multiple` option. :warning:
### Array-like Attributes
Array-like attributes with plain ruby objects:
```ruby
class User
extend Enumerizeenumerize :interests, in: [:music, :sports], multiple: true
enduser = User.new
user.interests << :music
user.interests << :sports
```and with ActiveRecord:
```ruby
class User < ActiveRecord::Base
extend Enumerizeserialize :interests, Array
enumerize :interests, in: [:music, :sports], multiple: true
end
```get an array of all text values:
```ruby
@user.interests.texts # shortcut for @user.interests.map(&:text)
```Also, the reader method can be overridden, referencing the enumerized attribute value using `super`:
```ruby
def status
if current_user.admin?
"Super #{super}"
else
super
end
end
```---
## Forms
### SimpleForm
If you are using SimpleForm gem you don't need to specify input type (`:select` by default) and collection:
```erb
<%= simple_form_for @user do |f| %>
<%= f.input :status %>
<% end %>
```and if you want it as radio buttons:
```erb
<%= simple_form_for @user do |f| %>
<%= f.input :status, as: :radio_buttons %>
<% end %>
```Please note that Enumerize overwrites the I18n keys of SimpleForm collections. The enumerized keys are used instead of the SimpleForm ones for inputs concerning enumerized attributes. If you don't want this just pass `:collection` option to the `input` call.
### Formtastic
If you are using Formtastic gem you also don't need to specify input type (`:select` by default) and collection:
```erb
<%= semantic_form_for @user do |f| %>
<%= f.input :status %>
<% end %>
```and if you want it as radio buttons:
```erb
<%= semantic_form_for @user do |f| %>
<%= f.input :status, as: :radio %>
<% end %>
```---
## Testing
### RSpec
Also you can use builtin RSpec matcher:
```ruby
class User
extend Enumerizeenumerize :status, in: [:student, :employed, :retired]
enddescribe User do
it { should enumerize(:status) }# or with RSpec 3 expect syntax
it { is_expected.to enumerize(:status) }
end
```#### Qualifiers
##### in
Use `in` to test usage of the `:in` option.
```ruby
class User
extend Enumerizeenumerize :status, in: [:student, :employed, :retired]
enddescribe User do
it { should enumerize(:status).in(:student, :employed, :retired) }
end
```You can test enumerized attribute value using custom values with the `in`
qualifier.```ruby
class User
extend Enumerizeenumerize :role, in: { user: 0, admin: 1 }
enddescribe User do
it { should enumerize(:role).in(user: 0, admin: 1) }
end
```##### with_default
Use `with_default` to test usage of the `:default` option.
```ruby
class User
extend Enumerizeenumerize :role, in: [:user, :admin], default: :user
enddescribe User do
it { should enumerize(:user).in(:user, :admin).with_default(:user) }
end
```##### with_i18n_scope
Use `with_i18n_scope` to test usage of the `:i18n_scope` option.
```ruby
class User
extend Enumerizeenumerize :status, in: [:student, :employed, :retired], i18n_scope: 'status'
enddescribe User do
it { should enumerize(:status).in(:student, :employed, :retired).with_i18n_scope('status') }
end
```##### with_predicates
Use `with_predicates` to test usage of the `:predicates` option.
```ruby
class User
extend Enumerizeenumerize :status, in: [:student, :employed, :retired], predicates: true
enddescribe User do
it { should enumerize(:status).in(:student, :employed, :retired).with_predicates(true) }
end
```You can text prefixed predicates with the `with_predicates` qualifiers.
```ruby
class User
extend Enumerizeenumerize :status, in: [:student, :employed, :retired], predicates: { prefix: true }
enddescribe User do
it { should enumerize(:status).in(:student, :employed, :retired).with_predicates(prefix: true) }
end
```##### with_scope
Use `with_scope` to test usage of the `:scope` option.
```ruby
class User
extend Enumerizeenumerize :status, in: [:student, :employed, :retired], scope: true
enddescribe User do
it { should enumerize(:status).in(:student, :employed, :retired).with_scope(true) }
end
```You can test a custom scope with the `with_scope` qualifiers.
```ruby
class User
extend Enumerizeenumerize :status, in: [:student, :employed], scope: :employable
enddescribe User do
it { should enumerize(:status).in(:student, :employed, :retired).with_scope(scope: :employable) }
end
```##### with_multiple
Use `with_multiple` to test usage of the `:multiple` option.
```ruby
class User
extend Enumerizeenumerize :status, in: [:student, :employed, :retired], multiple: true
enddescribe User do
it { should enumerize(:status).in(:student, :employed, :retired).with_multiple(true) }
end
```### Minitest with Shoulda
You can use the RSpec matcher with shoulda in your tests by adding two lines in your `test_helper.rb` inside `class ActiveSupport::TestCase` definition:
```ruby
class ActiveSupport::TestCase
ActiveRecord::Migration.check_pending!require 'enumerize/integrations/rspec'
extend Enumerize::Integrations::RSpec...
end
```### Other Integrations
Enumerize integrates with the following automatically:
- [RailsAdmin](https://github.com/sferik/rails_admin/)
---
## Contributing
1. Fork it
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Added some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create new Pull Request