|
| 1 | +module ActiveRecord |
| 2 | + # Declare an enum attribute where the values map to integers in the database, but can be queried by name. Example: |
| 3 | + # |
| 4 | + # class Conversation < ActiveRecord::Base |
| 5 | + # enum status: %i( active archived ) |
| 6 | + # end |
| 7 | + # |
| 8 | + # Conversation::STATUS # => { active: 0, archived: 1 } |
| 9 | + # |
| 10 | + # # conversation.update! status: 0 |
| 11 | + # conversation.active! |
| 12 | + # conversation.active? # => true |
| 13 | + # conversation.status # => :active |
| 14 | + # |
| 15 | + # # conversation.update! status: 1 |
| 16 | + # conversation.archived! |
| 17 | + # conversation.archived? # => true |
| 18 | + # conversation.status # => :archived |
| 19 | + # |
| 20 | + # # conversation.update! status: 1 |
| 21 | + # conversation.status = :archived |
| 22 | + # |
| 23 | + # You can set the default value from the database declaration, like: |
| 24 | + # |
| 25 | + # create_table :conversation do |
| 26 | + # t.column :status, :integer, default: 0 |
| 27 | + # end |
| 28 | + # |
| 29 | + # Good practice is to let the first declared status be the default. |
| 30 | + module Enum |
| 31 | + def enum(definitions) |
| 32 | + definitions.each do |name, values| |
| 33 | + const_name = name.to_s.upcase |
| 34 | + |
| 35 | + # DIRECTION = { } |
| 36 | + const_set const_name, {} |
| 37 | + |
| 38 | + # def direction=(value) self[:direction] = DIRECTION[value] end |
| 39 | + class_eval "def #{name}=(value) self[:#{name}] = #{const_name}[value] end" |
| 40 | + |
| 41 | + # def direction() DIRECTION.key self[:direction] end |
| 42 | + class_eval "def #{name}() #{const_name}.key self[:#{name}] end" |
| 43 | + |
| 44 | + values.each_with_index do |value, i| |
| 45 | + # DIRECTION[:incoming] = 0 |
| 46 | + const_get(const_name)[value] = i |
| 47 | + |
| 48 | + # scope :incoming, -> { where direction: 0 } |
| 49 | + scope value, -> { where name => i } |
| 50 | + |
| 51 | + # def incoming?() direction == 0 end |
| 52 | + class_eval "def #{value}?() self[:#{name}] == #{i} end" |
| 53 | + |
| 54 | + # def incoming! update! direction: :incoming end |
| 55 | + class_eval "def #{value}!() update! #{name}: :#{value} end" |
| 56 | + end |
| 57 | + end |
| 58 | + end |
| 59 | + end |
| 60 | +end |
0 commit comments