No commit activity in last 3 years
No release in over 3 years
A simpler way to create more complex Ruby enumerations, with ActiveRecord like syntax and associations.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Runtime

 Project Readme

ActiveEnumeration

A simpler way to create more complex Ruby enumerations, with ActiveRecord like syntax and associations.

Author: Peter Lin - peter at ptrln.net

Build Status

Description

There seems to be a lot of Ruby enumeration gems out there, but none of them solved what we needed, so I created this one to behave more similar to ActiveRecord models. You are able to define associations between enumerations, and any number of attributes, allowing much greater flexibility than existing solutions.

For example:

If you have to model Regions and their Locations, you could store this in your DB. However, these are essentially constants, and once created will never change. It seems silly to constantly hit the DB just to retrieve these.

ActiveEnumeration allows you to create these more complex enumerations easily, while maintaining associations, and various attributes that make these enumerations much more useful.

Creating enumerations

Enumerations are created as Plain Old Ruby Objects, so you can put them whereever you like.

class Region < ActiveEnumeration::Base
  has_many :locations

  attr_reader :id, :name, :area_name, :time_zone

  values ({
    :bay_area    => [ 1, 'Bay Area', "San Francisco Bay Area", "Pacific Time (US & Canada)"],
    :los_angeles => [ 2, 'Los Angeles', "Los Angeles Area", "Pacific Time (US & Canada)"],
    :new_york    => [ 3, 'New York', "New York City and Tri-State Area", "Eastern Time (US & Canada)"],
    :chicago     => [ 4, 'Chicago', "Chicago Area", "Central Time (US & Canada)"],
  })

  groups({
    :live => [1, 2],
  })

  def to_s
    self.name
  end

end
class Location < ActiveEnumeration::Base
  belongs_to :region
  
  attr_reader :id, :name, :region_id
  
  values ([
    # NY
    [ 1, 'Manhattan', 3],
    [ 2, 'Brooklyn', 3],
    [ 3, 'Bronx', 3],
    # SF
    [ 4, 'San Francisco', 1],
    [ 5, 'East Bay', 1],
    [ 6, 'South Bay', 1],
    # LA
    [ 7, 'Los Angeles County', 2],
    [ 8, 'Orange County', 2],
    # Chicago
    [ 9, "Greater Chicago Area", 4] 
  ])

end

This will create some nice stuff:

  • Each enumeration's value will turn into a constant:

    Region::BAY_AREA
    #=> 1
  • You can retrieve an enumeration:

    Region.bay_area
    #=> #<Region:0x007f9258b7dd50 @active_enumeration_id=1, @id=1, @name="Bay Area", @area_name="San Francisco Bay Area", @time_zone="Pacific Time (US & Canada)"> 
  • Or you can find based on the 'id':

    Region.find(1)
    #=> #<Region:0x007f9258b7dd50 @active_enumeration_id=1, @id=1, @name="Bay Area", @area_name="San Francisco Bay Area", @time_zone="Pacific Time (US & Canada)"> 
  • You can retrieve the attributes very easily:

    Region.bay_area.time_zone
    #=> "Pacific Time (US & Canada)"
  • You can retrieve has_many associated enumerations:

    Region.bay_area.locations
    #=> [#<Location:0x007f9258b9d448 @active_enumeration_id=4, @id=4, @name="San Francisco", @region_id=1>, #<Location:0x007f9258b9d240 @active_enumeration_id=5, @id=5, @name="East Bay", @region_id=1>, #<Location:0x007f9258b9cf98 @active_enumeration_id=6, @id=6, @name="South Bay", @region_id=1>] 
  • You can retrieve belongs_to associated enumerations:

    Location.find(1).region
    #=> #<Region:0x007f9258b86a18 @active_enumeration_id=3, @id=3, @name="New York", @area_name="New York City and Tri-State Area", @time_zone="Eastern Time (US & Canada)"> 
  • You can retrieve all enumerations:

    Region.all
    #=> [#<Region:0x007f9258b7dd50 @active_enumeration_id=1, @id=1, @name="Bay Area", @area_name="San Francisco Bay Area", @time_zone="Pacific Time (US & Canada)">, #<Region:0x007f9258b86db0 @active_enumeration_id=2, @id=2, @name="Los Angeles", @area_name="Los Angeles Area", @time_zone="Pacific Time (US & Canada)">, #<Region:0x007f9258b86a18 @active_enumeration_id=3, @id=3, @name="New York", @area_name="New York City and Tri-State Area", @time_zone="Eastern Time (US & Canada)">, #<Region:0x007f9258b86680 @active_enumeration_id=4, @id=4, @name="Chicago", @area_name="Chicago Area", @time_zone="Central Time (US & Canada)">]
  • You can get an array of options, ready to use with the Rails 'select' helpers.

    Region.to_a
    #=> [["Bay Area", 1], ["Los Angeles", 2], ["New York", 3], ["Chicago", 4]]
  • You can create groups for your enumerations.

    Region.live
    #=> [#<Region:0x007f9258b7dd50 @active_enumeration_id=1, @id=1, @name="Bay Area", @area_name="San Francisco Bay Area", @time_zone="Pacific Time (US & Canada)">, #<Region:0x007f9258b86db0 @active_enumeration_id=2, @id=2, @name="Los Angeles", @area_name="Los Angeles Area", @time_zone="Pacific Time (US & Canada)">]
  • You can filter your enumerations using 'where'.

    Location.where(region_id: 3, name: 'Manhattan')
    #=> [#<Location:0x007f9258b9d448 @active_enumeration_id=1, @id=1, @name="Manhattan", @region_id=3>,
  • You can ask for the enumeration's count:

    Region.count
    #=> 4

Using enumerations

You can use these enumerations with any class, however ActiveEnumeration expects an 'id' for each enumeration.

class Person
  extend ActiveEnumeration

  attr_accessor :region_id, :home_region_id, :location_id, :previous_location_ids

  has_active_enumeration_for  :region
  has_active_enumeration_for  :home_region, class_name: "Region"
  has_active_enumeration_for  :last_location, class_name: "Location", foreign_key: "location_id"
  has_active_enumerations_for :previous_locations, class_name: "Location"
  
  ...

end
  • You easily retrieve a Person's region:

    person.region
    #=> #<Region:0x007f9258b7dd50 @active_enumeration_id=1, @id=1, @name="Bay Area", @area_name="San Francisco Bay Area", @time_zone="Pacific Time (US & Canada)">
  • And through that, retrieve useful attributes.

    person.region.time_zone
    #=> "Pacific Time (US & Canada)"
  • Also helper methods that make checking these enumerations easier

    person.region.bay_area?
    #=> true
    
    person.region.chicago?
    #=> false

Using with Rails

  • Add the gem to your Gemfile:

    gem "active_enumeration"

Why did you make this gem?

There are other similar solutions to the problem out there, but I did not find any that included associations between enumerations. I also found learning a new syntax kind of annoying, so I thought it'll be nice to have everything work with ActiveRecord like syntax.

Benefits:

  • Take constants out of your DB, eliminate unnecessary DB reads.
  • You can add many more attributes to your enumeration class.
  • You can group your enumerations.
  • You can have associations between your enumerations.
  • No need to learn a new DSL, since most of the functionality behaves similarly to ActiveRecord.