Skip to content

Instantly share code, notes, and snippets.

@bryanstearns
Created April 9, 2009 07:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bryanstearns/92306 to your computer and use it in GitHub Desktop.
Save bryanstearns/92306 to your computer and use it in GitHub Desktop.
module EnumeratedAttributes
def self.included(base)
base.extend ClassMethods
end
module ClassMethods
def enumeration(attr_name, options)
# Declare a mapping of symbols to integer values for an attribute:
#
# enumeration :ghost,
# :in => {:past => 0, :present => 12, :yet_to_come => -5},
# :default => :present
#
# In the migration, declare an integer field with the same name and an
# "_enum" suffix:
# t.integer :ghost_enum, :default => MyModel::GHOST_DEFAULT_VALUE
#
# This gets you:
# - accessors for the field that return/accept symbols (and nil).
# - class constants on the model for the values, symbols, default value
# & default symbol
# - If you want to give the enumeration a different name (which only
# affects the names of the class constants
attr_name = attr_name.to_s.downcase
symbol_to_value = options.delete(:in)
value_to_symbol = symbol_to_value.invert
default = options.delete(:default)
enum_name = (options.delete(:enum_name) || attr_name).to_s.upcase
column_name = options.delete(:column_name) || "#{attr_name}_enum"
const_set("#{enum_name}_DEFAULT_SYMBOL", default)
const_set("#{enum_name}_DEFAULT_VALUE", symbol_to_value[default])
const_set("#{enum_name}_SYMBOLS", symbol_to_value.keys)
const_set("#{enum_name}_VALUES", symbol_to_value.values)
define_method(attr_name) do
value_to_symbol[self.send(column_name)]
end
define_method("#{attr_name}=") do |symbol|
self.send("#{column_name}=", symbol && symbol_to_value[symbol.to_sym])
end
end
def validates_enumeration(attr_name, options={})
# Validate the attribute with this, which accepts all of
# validates_inclusion_of's options, eg:
# validates_enumeration :ghost, :allow_nil => false
enum_name = options.delete(:enum_name) || attr_name
validates_inclusion_of attr_name,
options.merge(:in => const_get("#{enum_name.to_s.upcase}_SYMBOLS"))
end
end
end
class ActiveRecord::Base
include EnumeratedAttributes
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment