Module: ActiveRecord::VirtualEnumerations

Defined in:
lib/active_record/virtual_enumerations.rb

Overview

Implements a mechanism to synthesize enum classes for simple enums. This is for situations where you wish to avoid cluttering the models directory with your enums.

Create a custom Rails initializer: Rails.root/config/initializers/virtual_enumerations.rb

ActiveRecord::VirtualEnumerations.define do |config|
  config.define 'ClassName',
                :table_name        => 'table',
                :extends           => 'SuperclassName',
                :conditions        => ['something = ?', "value"],
                :order             => 'column ASC',
                :on_lookup_failure => :enforce_strict,
                :name_column       => 'name_column',
                :alias_name        => false {
    # class_evaled_functions
  }
end

Only the 'ClassName' argument is required. :table_name is used to define a custom table name while the :extends option is used to set a custom superclass. Class names can be either camel-cased like ClassName or with underscores, like class_name. Strings and symbols are both fine.

If you need to fine-tune the definition of the enum class, you can optionally pass in a block, which will be evaluated in the context of the enum class.

Example:

config.define :color, :on_lookup_failure => :enforce_strict, do
  def to_argb(alpha)
    case self.to_sym
    when :white
      [alpha, 255, 255, 255]
    when :red
      [alpha, 255, 0, 0]
    when :blue
      [alpha, 0, 0, 255]
    when :yellow
      [alpha, 255, 255, 0]
    when :black
      [alpha, 0, 0, 0]
    end
  end
end

As a convenience, if multiple enums share the same configuration, you can pass all of them to config.define.

Example:

config.define :booking_status, :connector_type, :color, :order => :name

Single Table Inheritance is also supported:

Example:

config.define :base_enum, :name_column => ;foo
config.define :booking_status, :connector_type, :color, :extends => :base_enum

Defined Under Namespace

Classes: Config

Class Method Summary collapse

Class Method Details

.define {|config| ... } ⇒ Object

Defines enumeration classes. Passes a config object to the given block which is used to define the virtual enumerations. Call config.define for each enum or enums with a given set of options.

Yields:

  • (config)

Raises:

  • (ArgumentError)


94
95
96
97
98
99
100
# File 'lib/active_record/virtual_enumerations.rb', line 94

def self.define
  raise ArgumentError, "#{self.name}: must pass a block to define()" unless block_given?
  patch_const_lookup
  config = ActiveRecord::VirtualEnumerations::Config.new
  yield config
  @config = config # we only overwrite config if no exceptions were thrown
end

.patch_const_lookupObject

Patches Module#const_missing to enable us to dynamically create enum classes at runtime.



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/active_record/virtual_enumerations.rb', line 69

def self.patch_const_lookup
  # Make sure we haven't patched Module already
  unless ::Module.respond_to?(:enumerations_original_const_missing)
    # patch Module to support VirtualEnumerations
    ::Module.module_eval do

      alias_method :enumerations_original_const_missing, :const_missing

      # Override const_missing to see if VirtualEnumerations can create it.
      def const_missing(const_id)
        # let rails have a go at loading it
        enumerations_original_const_missing(const_id)
      rescue NameError
        # now it's our turn
        ActiveRecord::VirtualEnumerations.synthesize_if_defined(const_id) or raise
      end

    end
  end

end

.synthesize_if_defined(const) ⇒ Object

Creates a constant for a virtual enum if a config is defined for it.



103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/active_record/virtual_enumerations.rb', line 103

def self.synthesize_if_defined(const)
  if @config && options = @config[const]
    class_declaration = "class #{const} < #{options[:extends]}; end"

    eval( class_declaration, TOPLEVEL_BINDING, __FILE__, __LINE__ )

    virtual_enum_class = const_get( const )

    inject_class_options( virtual_enum_class, options )

    virtual_enum_class
  else
    nil
  end
end