enum_id
Defines an enumerated field (stored as an integral id). The field is defined by its name (which must be the column name without the _id suffix), and a hash which maps the id valid values of the field to symbolic constants. The hash can also contain options with symbolic keys; currently the only valid option is :required which checks for non-nil values at validation; if a value other than true is assigned to it, it should be a hash with options that will be relayed to validates_presence_of
Example: (we assume that the table for X has an integer column named ‘status_id’)
class X < ActiveRecord::Base
enum_id :status, 1=>:first, 2=>:second, 3=>:third, :required=>true
end
This is equivalent to:
class X < ActiveRecord::Base
# Return the symbolic status value
def status
X.status(status_id)
end
# Assigns the symbolic status value and also accepts status ids
def status=(st)
self.status_id = X.status_id(st)
end
# Returns the status description (must be provided as a translation)
def status_name
X.status_name(status_id)
end
ENUM_ID_status_SYMBOLS = {1=>:first, 2=>:second, 3=>:third}
ENUM_ID_status_IDS = {:first=>1, :second=>2, :third=>3}
# Return the symbolic status for a status id
def X.status(id)
id && (ENUM_ID_status_SYMBOLS[id.to_i] || raise("Invalid status id: #{id}"))
end
# Return the status id for a symbolic status (or status id)
def X.status_id(st)
st && if st.kind_of?(Integer)
raise "Invalid status id: #{st}" unless X.status_ids.include?(st)
st
elsif st.kind_of?(Symbol)
ENUM_ID_status_IDS[st.to_sym] || raise("Invalid status: #{st.inspect}")
else
raise TypeError,"Integer or Symbol argument expected (got a #{st.class.name})."
end
end
# Return the symbolic status given a status symbol or id
def X.status_symbol(st)
st && (st.kind_of?(Integer) ? status(st) : st.to_sym)
end
# Return the description of a status symbol or id
def X.status_name(st)
st = status_symbol(st)
st && I18n.t("enum_id.x.status.#{st}")
end
# Return all the valid status ids in an Array [1,2,3]
def X.status_ids
ENUM_ID_status_SYMBOLS.keys.sort
end
# Return all the valid status symbols in an Array: [:first, :second, :third]
def X.status_symbols
status_ids.map{|id| status_symbol(id)}
end
# Define accessors for all status values: first?, second?, third?
X.status_symbols.each do |stat|
define_method :"#{stat}?" do
status == :"#{stat}"
end
end
# Define validations
validates_inclusion_of :status_id, :in=>X.status_ids
end
To use the _name methods we’d need to add this to config/locales/en.yml (and any other required languages):
enum_id:
x:
status:
first: "Description of first status"
second: "Description of second status"
third: "Description of third status"