Module: ClassyEnum::ActiveRecord

Defined in:
lib/classy_enum/active_record.rb

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.included(klass) ⇒ Object


31
32
33
# File 'lib/classy_enum/active_record.rb', line 31

def self.included(klass)
  klass.extend self
end

Instance Method Details

#classy_enum_attr(attribute, options = {}) ⇒ Object

# Associate an enum Priority with Alarm model's alarm_priority attribute

classy_enum_attr :alarm_priority, class_name: 'Priority'

# Allow enum value to be nil
classy_enum_attr :priority, allow_nil: true

# Allow enum value to be blank
classy_enum_attr :priority, allow_blank: true

# Specifying a default enum value
classy_enum_attr :priority, default: 'low'

60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/classy_enum/active_record.rb', line 60

def classy_enum_attr(attribute, options={})
  enum              = (options[:class_name] || options[:enum] || attribute).to_s.camelize.constantize
  allow_blank       = options[:allow_blank] || false
  allow_nil         = options[:allow_nil] || false
  default           = ClassyEnum._normalize_default(options[:default], enum)

  # Add ActiveRecord validation to ensure it won't be saved unless it's an option
  validates_inclusion_of attribute,
    in:          enum,
    allow_blank: allow_blank,
    allow_nil:   allow_nil

  # Use a module so that the reader methods can be overridden in classes and
  # use super to get the enum value.
  mod = Module.new do

    # Define getter method that returns a ClassyEnum instance
    define_method attribute do
      enum.build(read_attribute(attribute), owner: self)
    end

    # Define setter method that accepts string, symbol, instance or class for member
    define_method "#{attribute}=" do |value|
      value = ClassyEnum._normalize_value(value, default, (allow_nil || allow_blank))
      super(value)
    end

    define_method :save_changed_attribute do |attr_name, arg|
      if attribute.to_s == attr_name.to_s && !attribute_changed?(attr_name)
        arg = enum.build(arg)
        current_value = clone_attribute_value(:read_attribute, attr_name)

        if arg != current_value
          if respond_to?(:set_attribute_was, true)
            set_attribute_was(attr_name, enum.build(arg, owner: self))
          else
            changed_attributes[attr_name] = enum.build(current_value, owner: self)
          end
        end
      else
        super(attr_name, arg)
      end
    end
  end

  include mod

  # Initialize the object with the default value if it is present
  # because this will let you store the default value in the
  # database and make it searchable.
  if default.present?
    after_initialize do
      value = read_attribute(attribute)

      if (value.blank? && !(allow_blank || allow_nil)) || (value.nil? && !allow_nil)
        send("#{attribute}=", default)
      end
    end
  end

end