Skip to content

Instantly share code, notes, and snippets.

@dnagir
Created February 8, 2012 23:44
Show Gist options
  • Save dnagir/1775540 to your computer and use it in GitHub Desktop.
Save dnagir/1775540 to your computer and use it in GitHub Desktop.
Symbols and enums
module HasSymbolicField
extend ActiveSupport::Concern
module ClassMethods
# Defining (all below are equivalent):
# - has_symbolic_field :status, [:active, :pending]
# - has_symbolic_field :status, :active => 'Active', :pending => 'Pending'
# - has_symbolic_field :status, :active => 'Active', :pending => nil
# Accessing:
# - it.status # :available
# - it.status = :pending
# - it.status = 'available'
# - it.status_name # "Available"
# - it.status_hash.keys # [:active, :pending]
# - it.status_hash.values # ["Active", "Pending"]
# - it.status_allowed? :random # false
# - it.status = :random # error
def has_symbolic_field(field, options={})
clazz = self
options ||= {}
raise "Please provide the available options hash for #{clazz.name}##{field}." if options.empty?
# For array, convert it to Hash magically
options = Hash[ options.map {|v| [v.to_s.underscore.to_sym, v.to_s.humanize] } ] unless options.respond_to? :keys
options.each_pair do |k,v|
options[k] = k.to_s.humanize if v.blank?
end
# Create a closure
defining = lambda {
clazz.send(:define_method, "#{field}_allowed?") do |value|
return true if value.blank?
options.keys.include? value.to_sym
end
clazz.send(:define_method, "#{field}_name") do
key = read_attribute(field).try(:to_sym)
options[key]
end
clazz.send(:define_method, "#{field}_hash") do
options
end
clazz.class.send(:define_method, "#{field}_hash") do
options
end
clazz.send(:define_method, field) do
read_attribute(field).try(:to_sym)
end
clazz.send(:define_method, "#{field}=") do |value|
raise "The value '#{value}' for #{clazz.name}##{field} is not allowed." unless send("#{field}_allowed?", value)
write_attribute field, value.try(:to_s)
end
}
defining.call
end
end
end
::ActiveRecord::Base.send(:include, HasSymbolicField)
class User < ActiveRecord::Base
has_symbolic_field :category, {
admin: 'Administrators',
managers: 'Sales Managers',
sales: 'Sales Staff',
external: 'External Networks'
}
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment