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"