Module: Mongoid::Enum::ClassMethods

Defined in:
lib/mongoid/enum.rb

Overview

:nodoc:

Instance Method Summary collapse

Instance Method Details

#enum(definitions) ⇒ Object

Define enum field on the model. See description of Mongoid::Enum



142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
# File 'lib/mongoid/enum.rb', line 142

def enum(definitions)
  klass = self
  enum_prefix = definitions.delete(:_prefix)
  enum_suffix = definitions.delete(:_suffix)
  default_key = definitions.delete(:_default)
  pluralize   = definitions.delete(:_plural_scopes)

  definitions.each do |name, values|
    enum_values = ActiveSupport::HashWithIndifferentAccess.new
    name        = name.to_sym
    const_name  = name.to_s.pluralize.upcase

    if klass.const_defined?(const_name)
      fail ArgumentError, "Defining enum :#{name} on #{klass} would " \
        "overwrite existing constant #{klass}::#{const_name}"
    end

    detect_enum_conflict!(name, name)
    detect_enum_conflict!(name, "#{name}=")

    if values.respond_to? :each_pair
      values.each_pair { |key, value| enum_values[key.to_s] = value }
    else
      values.each { |v| enum_values[v.to_s] = v.to_s }
    end

    enum_values.each do |key, value|
      key.freeze
      value.freeze
    end
    enum_values.freeze

    if default_key && !enum_values.key?(default_key)
      fail ArgumentError, "default key #{default_key} is not among enum options"
    end

    field name, type: EnumType.new(enum_values), default: default_key

    klass.const_set const_name, enum_values
    klass.validates name,
                    inclusion: {
                      in: enum_values.keys,
                      allow_nil: true,
                      message: "is invalid"
                    }

    _enum_methods_module.module_eval do
      enum_values.each do |key, value|
        if enum_prefix == true
          prefix = "#{name}_"
        elsif enum_prefix
          prefix = "#{enum_prefix}_"
        end
        if enum_suffix == true
          suffix = "_#{name}"
        elsif enum_suffix
          suffix = "_#{enum_suffix}"
        end

        value_method_name = "#{prefix}#{key}#{suffix}"
        scope_name = pluralize ? value_method_name.pluralize : value_method_name

        # def active?() status == 0 end
        klass.send(:detect_enum_conflict!, name, "#{value_method_name}?")
        define_method("#{value_method_name}?") { self[name] == value }

        # def active!() update! status: :active end
        klass.send(:detect_enum_conflict!, name, "#{value_method_name}!")
        define_method("#{value_method_name}!") { update! name => key }

        # scope :active, -> { where status: 0 }
        klass.send(:detect_enum_conflict!, name, scope_name, true)
        klass.scope scope_name, -> { klass.where name => key }
      end
    end

    # dup so children classes don't add their own enums to parent definitions
    self.enums = enums.dup

    enums[name] = enum_values
    enums.freeze
  end
end