public
Rubygem
Description: Adds support for declaring an ActiveRecord class as an enumeration
Homepage: http://www.pluginaweek.org
Clone URL: git://github.com/pluginaweek/enumerate_by.git
name age message
file .gitignore Fri Jul 04 15:49:48 -0700 2008 Ignore test/app_root/script [obrie]
file CHANGELOG.rdoc Sun Jun 14 17:12:18 -0700 2009 Tag 0.4.3 release [obrie]
file LICENSE Loading commit data...
file README.rdoc
file Rakefile
file enumerate_by.gemspec
file init.rb
directory lib/
directory test/

enumerate_by

enumerate_by adds support for declaring an ActiveRecord class as an enumeration.

Resources

API

Bugs

Development

Source

  • git://github.com/pluginaweek/enumerate_by.git

Description

Support for enumerations is dependent on the type of database you use. For example, MySQL has native support for the enum data type. However, there is no native Rails support for defining enumerations and the associations between it and other models in the application.

In addition, enumerations may often have more complex data and/or functionality associated with it that cannot simply be describe in a single column.

enumerate_by adds support for pseudo-enumerations in Rails by allowing the enumeration’s records to be defined in code, but continuing to express the relationship between an enumeration and other models using ActiveRecord associations. The important thing to remember, however, is that while the associations exist, the enumerator is always used outside of the application, while either the enumerator or the enumerator’s record would be referenced within the application. This means that you would reference a Color record via it’s enumerator (such as "red") everywhere in the code (conditions, assigning associations, forms, etc.), but it would always be stored in the database as a true association with the integer value of 1.

Usage

  class Color < ActiveRecord::Base
    enumerate_by :name

    belongs_to :group, :class_name => 'ColorGroup'
    has_many :cars

    bootstrap(
      {:id => 1, :name => 'red', :group => 'RGB'},
      {:id => 2, :name => 'blue', :group => 'RGB'},
      {:id => 3, :name => 'green', :group => 'RGB'},
      {:id => 4, :name => 'cyan', :group => 'CMYK'}
    )
  end

  class ColorGroup < ActiveRecord::Base
    enumerate_by :name

    has_many :colors, :foreign_key => 'group_id'

    bootstrap(
      {:id => 1, :name => 'RGB'},
      {:id => 2, :name => 'CMYK'}
    )
  end

  class Car < ActiveRecord::Base
    belongs_to :color
  end

Each of the above models is backed by the database with its own table. Both the Color and ColorGroup enumerations automatically synchronize with the records in the database based on what’s define in their bootstrap data.

The enumerations and their associations can be then be used like so:

  car = Car.create(:color => 'red')   # => #<Car id: 1, color_id: 1>
  car.color                           # => #<Color id: 1, name: "red">
  car.color == 'red'                  # => true
  car.color.name                      # => "red"

  car.color = 'blue'
  car.save                            # => true
  car                                 # => #<Car id: 1, color_id: 2>

  # Serialization
  car.to_json                         # => "{id: 1, color: \"blue\"}"
  car.to_xml                          # => "<car><id type=\"integer\">1</id><color>blue</color></car>"

  # Lookup
  Car.with_color('blue')              # => [#<Car id: 1, color_id: 2>]
  car = Car.find_by_color('blue')     # => #<Car id: 1, color_id: 2>
  car.color == Color['blue']          # => true

As mentioned previously, the important thing to note from the above example is that from an external perspective, "color" is simply an attribute on the Car. However, it’s backed by a more complex association and model that allows Color to include advanced functionality that would normally not be possible with a simple attribute.

Testing

Before you can run any tests, the following gem must be installed:

To run against a specific version of Rails:

  rake test RAILS_FRAMEWORK_ROOT=/path/to/rails

Dependencies

  • Rails 2.1 or later