Enumerize

repository·master·Indexed 23 days ago

https://github.com/brainspec/enumerize

A Ruby library for defining enumerated attributes on models with support for validation, conversion, and I18n. It integrates with ActiveRecord, Mongoid, MongoMapper, and ActiveModel::Attributes, providing helper methods for human-readable labels and raw values. Supports Ruby 3.1+ and Rails 7.0+, and includes built-in RSpec matchers for testing attribute configurations.

Tokens
5.1K
Snippets
11
Records
30
Agent score
82%

What's inside enumerize

  1. Configure I18n for Enumerated Attributes

    master

    To provide human-readable labels for enumerators, use I18n localization files. You can scope translations by the model name or use a defaults scope for shared attributes.

    Use the i18n_scope option to specify where translations are stored. This can be a string, an array of strings, or a proc that returns a string.

    Note: For plain Ruby objects (non-ActiveRecord/Mongoid), you must also extend ActiveModel::Naming to enable I18n support.

    # Localization file structure (en.yml)
    en:
      enumerize:
        user:
          status:
            student: "Student"
            employed: "Employed"
            retired: "Retiree"
    
    # Usage with custom scope
    class Person
      extend Enumerize
      extend ActiveModel::Naming
    
      enumerize :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
  2. Use Enumerize with ActiveRecord

    master

    When using ActiveRecord, ensure your migration creates a column (typically a string) for the attribute. You can provide a default value, which can be a static symbol or a lambda that accepts the model instance.

    Important: By default, enumerize adds an inclusion validation. To skip this, use the skip_validations option (can be a boolean or a lambda).

    class User < ActiveRecord::Base
      extend Enumerize
    
      # Using a lambda for dynamic default
      enumerize :status, in: [:student, :employed, :retired], default: lambda { |user| StatusIdentifier.status_for_age(user.age).to_sym }
    
      # Using a static default
      enumerize :role, in: [:user, :admin], default: :user
    
      # Skipping validations conditionally
      enumerize :status, in: [:student, :employed, :retired], skip_validations: lambda { |user| user.new_record? }
    
      # Skipping validations entirely
      enumerize :role, in: [:user, :admin], skip_validations: true
    end
  3. Install Enumerize

    master

    To use Enumerize in your Ruby application, add it to your Gemfile:

    gem 'enumerize'

    Then run bundle install. Alternatively, you can install it directly via the command line:

    $ gem install enumerize

    Supported Versions:

    • Ruby 3.1+
    • Rails 7.0+
    gem 'enumerize'
  4. Use Enumerize with Minitest and Shoulda

    master

    To use the RSpec matchers within Minitest (specifically when using shoulda), add the following configuration to your test_helper.rb inside the ActiveSupport::TestCase class definition:

    class ActiveSupport::TestCase
      ActiveRecord::Migration.check_pending!
    
      require 'enumerize/integrations/rspec'
      extend Enumerize::Integrations::RSpec
    
      # ...
    end
    class ActiveSupport::TestCase
      ActiveRecord::Migration.check_pending!
    
      require 'enumerize/integrations/rspec'
      extend Enumerize::Integrations::RSpec
    
      ...
    end
  5. Test Enumerize with RSpec

    master

    Enumerize provides a built-in RSpec matcher to verify that attributes are correctly enumerated. You can use the standard should enumerize(:attribute) syntax or the RSpec 3 is_expected.to enumerize(:attribute) syntax.

    To use it, ensure your class extends Enumerize and then use the matcher in your describe blocks.

    class User
      extend Enumerize
    
      enumerize :status, in: [:student, :employed, :retired]
    end
    
    describe User do
      it { should enumerize(:status) }
    
      # or with RSpec 3 expect syntax
      it { is_expected.to enumerize(:status) }
    end
  6. ActiveRecord integration for Enumerize

    master

    When using Enumerize with ActiveRecord, the enumerize method is enhanced to provide seamless integration with ActiveRecord's lifecycle and type casting.

    Key behaviors include:

    • Automatic Type Casting: Enumerized attributes are integrated into the ActiveRecord type system, ensuring that values assigned to the attribute are correctly cast to Enumerize::Value objects.
    • Lifecycle Support: Enumerize uses after_initialize to set default values, ensuring compatibility with how Rails allocates and initializes models.
    • Relation Support: The integration extends ActiveRecord::Relation (and associated proxy classes) to ensure that bulk updates via update_all correctly translate human-readable values into their underlying database values.
    • Attribute Persistence: It handles complex scenarios like ActiveRecord::Store (stored attributes) and ensures that reload correctly restores enumerized values from the database or the store.
  7. How Enumerize handles ActiveModel serialization and casting

    master

    When used with ActiveModel::Attributes, Enumerize provides a custom type that manages the lifecycle of the attribute value:

    • Casting: When a value is assigned, it attempts to find the corresponding enumerized value. For attributes with multiple: true, it uses find_values to process arrays.
    • Deserialization: When reading from the database/source, it converts the raw value back into the enumerized object. If the attribute is marked as multiple: true and the value is an Array, it uses find_values.
    • Serialization: When saving, it uses the underlying value of the enumerized object (via find_value(value).value) to ensure the correct primitive is stored.
  8. How Enumerize::Value handles equality and JSON serialization

    master

    The Enumerize::Value class is a specialized String object used to represent an enumerated item. It is designed to behave like its underlying string value for most operations but provides specific logic for equality and serialization:

    • Equality: The == operator checks if the object matches another object by comparing the string representation or the underlying @value.
    • JSON Serialization: When converted to JSON via as_json, the object serializes to its string representation.
    • Encoding: It supports encode_with for custom encoding (e.g., in YAML), representing the object via its superclass and the underlying @value.
  9. How Enumerize handles ActiveRecord type casting

    master

    Enumerize implements a custom ActiveRecord::Type::Value subclass to manage the conversion between database values and Enumerize::Value objects.

    When a value is assigned to an enumerized attribute, the cast logic follows this priority:

    1. If the value is already an instance of Enumerize::Value, it is returned as-is.
    2. It attempts to find the value directly using the attribute's find_value method.
    3. If not found, it delegates to the attribute's subtype (if applicable) to attempt to cast the value before searching again.

    This ensures that both strings (like 'active') and integers (like 1) can be correctly resolved to the appropriate Enumerize::Value object.

  10. Extend a class with Enumerize

    master
    To add enumeration capabilities to a class, use extend Enumerize instead of include Enumerize (the latter is deprecated). Extending a class with Enumerize automatically includes Enumerize::Base and extends the class with Enumerize::Predicates. It also provides automatic support for various ORMs and frameworks if they are defined in your environment (such as ActiveRecord, Mongoid, Sequel, or ActiveModel).
  11. Integrate Enumerize with SimpleForm

    master

    Enumerize provides an extension for SimpleForm::FormBuilder that automatically configures input options for enumerated attributes. When using input or input_field in a SimpleForm builder, the extension automatically detects if an attribute is enumerated and applies the following logic:

    1. Automatic Collections: It populates the :collection option with the enumerated attribute's options.
    2. Multiple Selection Support: If the attribute is defined as Enumerize::Multiple, it automatically adds multiple: true to the :input_html options, unless you have explicitly set :as => :check_boxes.