Skip to content

Instantly share code, notes, and snippets.

@deecewan
Last active June 12, 2017 04:25
Show Gist options
  • Save deecewan/6baa54bc7253ba61f44258b301027cb9 to your computer and use it in GitHub Desktop.
Save deecewan/6baa54bc7253ba61f44258b301027cb9 to your computer and use it in GitHub Desktop.
Rails enum
# File activerecord/lib/active_record/enum.rb, line 146
# https://github.com/rails/rails/blob/919a876a04d991bb5a984314ca985168cfbbbef5/activerecord/lib/active_record/enum.rb#L146
# rails 5 backport so we can get the _prefix and _suffix features
if Rails::VERSION::MAJOR < 5
module ActiveRecord
module Enum
def enum(definitions)
klass = self
enum_prefix = definitions.delete(:_prefix)
enum_suffix = definitions.delete(:_suffix)
definitions.each do |name, values|
# statuses = { }
enum_values = ActiveSupport::HashWithIndifferentAccess.new
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) { enum_values }
_enum_methods_module.module_eval do
# BEGIN from Rails 4 http://apidock.com/rails/v4.2.7/ActiveRecord/Enum/enum
# def status=(value) self[:status] = statuses[value] end
klass.send(:detect_enum_conflict!, name, "#{name}=")
define_method("#{name}=") { |value|
if enum_values.has_key?(value) || value.blank?
self[name] = enum_values[value]
elsif enum_values.has_value?(value)
# Assigning a value directly is not a end-user feature, hence it's not documented.
# This is used internally to make building objects from the generated scopes work
# as expected, i.e. +Conversation.archived.build.archived?+ should be true.
self[name] = value
else
raise ArgumentError, "'#{value}' is not a valid #{name}"
end
}
# def status() statuses.key self[:status] end
klass.send(:detect_enum_conflict!, name, name)
define_method(name) { enum_values.key self[name] }
# def status_before_type_cast() statuses.key self[:status] end
klass.send(:detect_enum_conflict!, name, "#{name}_before_type_cast")
define_method("#{name}_before_type_cast") { enum_values.key self[name] }
# END from Rails 4 http://apidock.com/rails/v4.2.7/ActiveRecord/Enum/enum
pairs = values.respond_to?(:each_pair) ? values.each_pair : values.each_with_index
pairs.each do |value, i|
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}#{value}#{suffix}"
enum_values[value] = i
# def active?() status == 0 end
klass.send(:detect_enum_conflict!, name, "#{value_method_name}?")
define_method("#{value_method_name}?") { self[name] == i }
# def active!() update! status: :active end
klass.send(:detect_enum_conflict!, name, "#{value_method_name}!")
define_method("#{value_method_name}!") { update! name => value }
# scope :active, -> { where status: 0 }
klass.send(:detect_enum_conflict!, name, value_method_name, true)
klass.scope value_method_name, -> { klass.where name => i }
end
end
defined_enums[name.to_s] = enum_values
end
end
end
end
else
ActiveSupport::Deprecation.warn("Can remove Enum backport since we are on Rails 5 now.")
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment