module ActiveRecord::VirtualEnumerations
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
Public Class Methods
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.
# File lib/active_record/virtual_enumerations.rb, line 92 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
Patches Module#const_missing to enable us to dynamically create enum classes at runtime.
# File lib/active_record/virtual_enumerations.rb, line 67 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
Creates a constant for a virtual enum if a config is defined for it.
# File lib/active_record/virtual_enumerations.rb, line 101 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
Private Class Methods
Evals the given set of options within the context of the given class @private
# File lib/active_record/virtual_enumerations.rb, line 119 def self.inject_class_options( virtual_enum_class, options ) # Declare it acts_as_enumerated virtual_enum_class.class_eval do acts_as_enumerated :conditions => options[:conditions], :order => options[:order], :on_lookup_failure => options[:on_lookup_failure], :name_column => options[:name_column], :alias_name => options[:table_name] end # If necessary, set the table name unless (table_name = options[:table_name]).blank? virtual_enum_class.class_eval do self.table_name = table_name end end if block = options[:customizations_block] virtual_enum_class.class_eval(&block) end end
Public Instance Methods
Override const_missing
to see if VirtualEnumerations
can create it.
# File lib/active_record/virtual_enumerations.rb, line 76 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