Module: ActiveRecord::StringEnum

Defined in:
lib/active_record/string_enum.rb,
lib/active_record/string_enum/version.rb

Overview

Declare an enum attribute where the values map to integers in the database, but can be queried by name. Example:

class Conversation < ActiveRecord::Base
  enum status: [ :active, :archived ]
end

# conversation.update! status: :active
conversation.active!
conversation.active? # => true
conversation.status  # => "active"

# conversation.update! status: :archived
conversation.archived!
conversation.archived? # => true
conversation.status    # => "archived"

# conversation.update! status: :archived
conversation.status = "archived"

# conversation.update! status: nil
conversation.status = nil
conversation.status.nil? # => true
conversation.status      # => nil

Scopes based on the allowed values of the enum field will be provided as well. With the above example:

Conversation.active
Conversation.archived

Of course, you can also query them directly if the scopes doesn’t fit your needs:

Conversation.where(status: [:active, :archived])
Conversation.where.not(status: :active)

You can set the default value from the database declaration, like:

create_table :conversations do |t|
  t.column :status, :string, default: :active
end

In rare circumstances you might need to access the mapping directly. The mappings are exposed through a class method with the pluralized attribute name.

Conversation.statuses[0] # => :active
Conversation.statuses[1] # => :archived

Defined Under Namespace

Classes: EnumType

Constant Summary collapse

VERSION =
"0.0.2"

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.extended(base) ⇒ Object

:nodoc:



58
59
60
61
# File 'lib/active_record/string_enum.rb', line 58

def self.extended(base) # :nodoc:
  base.class_attribute(:defined_str_enums)
  base.defined_str_enums = {}
end

Instance Method Details

#inherited(base) ⇒ Object

:nodoc:



63
64
65
66
# File 'lib/active_record/string_enum.rb', line 63

def inherited(base) # :nodoc:
  base.defined_str_enums = defined_str_enums.deep_dup
  super
end

#str_enum(definitions) ⇒ Object



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/active_record/string_enum.rb', line 98

def str_enum(definitions)
  klass = self
  definitions.each do |name, values|
    # statuses = [ ]
    enum_values = values.map(&:to_s)
    name        = name.to_sym

    # def self.statuses statuses end
    detect_enum_conflict!(name, name.to_s.pluralize, true)
    klass.singleton_class.send(:define_method, name.to_s.pluralize) { values }

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

    # TODO: in Rails 4.2.1 this will be legal:
    # attribute name, EnumType.new(name, enum_values)
    # instead of the next lines:
    type = EnumType.new(name, enum_values)
    define_method("#{name}=") do |value|
      write_attribute(name, type.cast(value))
    end

    define_method(name) { type.deserialize(self[name]) }

    _enum_methods_module.module_eval do
      enum_values.each do |value|
        # def active?() status == :active end
        klass.send(:detect_enum_conflict!, name, "#{value}?")
        define_method("#{value}?") { self[name] == value }

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

        # scope :active, -> { where status: :active }
        klass.send(:detect_enum_conflict!, name, value, true)
        klass.scope value, -> { klass.where name => value }
      end
    end
    defined_str_enums[name.to_s] = enum_values
  end
end