Module: Enum::AttrSupport
- Defined in:
- lib/iron/enum/attr_support.rb
Overview
Provides helper methods to integrate enumerated constants (Enum) into your model layer. Given an enum defined like so:
module UserType
enum :guest, 0
enum :member, 1
enum :admin, 2
end
To add an enumerated value to a Rails model, simply add a column of type :integer to your model, then declare it like so:
class User < ActiveRecord::Base
enum_attr :user_type => UserType
end
When using non-model classes, it’s the same syntax:
class User
enum_attr :user_type => UserType
end
This will tell your class/model that the user_type attribute contains values from the UserType enum, and will add:
@user.user_type => integer value or nil
@user.user_type_admin? => true if object's user_type value == UserType::ADMIN
@user.user_type_admin! => set the object's user_type to be UserType::ADMIN (does not save model!)
@user.user_type_as_key => returns the key form of the current field value, eg :member
@user.user_type_as_name => returns text name of the current field's value, eg 'Guest'
In addition, you can set enum attributes via key, eg:
@user.user_type = :admin
and the key will be converted to a value on the fly.
ActiveRecord models get a few extras. To start, each enum attribute will add a smart scope:
User.with_user_type(UserType::MEMBER) => scope returning a relation selecting User instances where user_type's value == UserType::MEMBER
In addition, enum attributes will show up in #inspect output as e.g. UserType::GUEST instead of 0.
Instance Method Summary collapse
-
#enum_attr(field_to_enum_map) ⇒ Object
Call with enum_attr :field => Enum.
-
#enum_attr?(name) ⇒ Boolean
True if the given symbol maps to an enum-backed attribute.
-
#enum_for_attr(name) ⇒ Object
Gets the enum class for a given attribute, or nil for none.
Instance Method Details
#enum_attr(field_to_enum_map) ⇒ Object
Call with enum_attr :field => Enum
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 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 |
# File 'lib/iron/enum/attr_support.rb', line 48 def enum_attr(field_to_enum_map) # Save off the attr map @enum_attrs ||= {} @enum_attrs.merge!(field_to_enum_map) # Run each newly added enum attribute field_to_enum_map.each_pair do |attr_field, enum| # Convert Enum to "Enum" enum_klass = enum.to_s # Set up general use sugar - allows calling: # attr_as_key to get back eg :production or :online instead of 1 or 5 # attr_as_name to get back eg "Production" or "Online" class_eval " def \#{attr_field}_as_key\n \#{enum_klass}.key(self.\#{attr_field})\n end\n\n def \#{attr_field}_as_name\n \#{enum_klass}.name(self.\#{attr_field})\n end\n eos\n\n # Get all the possible values for this enum in :key format (ie as symbols)\n enum.keys.each do |key|\n # Get the value for this key (ie in integer format)\n val = enum.value(key)\n\n # Build sugar for testing and setting the attribute's enumerated value\n class_eval <<-eos, __FILE__, __LINE__ + 1\n def \#{attr_field}_\#{key}?\n self.\#{attr_field} == \#{val}\n end\n\n def \#{attr_field}_\#{key}!\n self.\#{attr_field} = \#{val}\n end\n eos\n end\n\n if defined?(ActiveRecord) && self < ActiveRecord::Base\n\n # Define a finder scope\n scope \"with_\#{attr_field}\", lambda {|*vals|\n vals.flatten!\n if vals.empty?\n where(\"?\", false)\n elsif vals.count == 1\n where(attr_field => enum.value(vals.first))\n else\n where(attr_field => enum.values(vals))\n end\n }\n \n # Define a validation\n validates attr_field, :inclusion => { \n :in => enum.values,\n :message => \"%{value} is not a valid \#{enum_klass} value\",\n :allow_nil => true\n }\n\n # Override default setter to allow setting an enum attribute via key\n class_eval <<-eos, __FILE__, __LINE__ + 1\n def \#{attr_field}=(val)\n write_attribute(:\#{attr_field}, \#{enum_klass}.value(val))\n end\n eos\n\n else \n\n # Create getter/setter to allow setting an enum attribute via key\n class_eval <<-eos, __FILE__, __LINE__ + 1\n def \#{attr_field}\n @\#{attr_field}\n end\n\n def \#{attr_field}=(val)\n val = nil if val.is_a?(String) && val.empty?\n @\#{attr_field} = \#{enum_klass}.value(val)\n end\n eos\n\n end\n\n end\nend\n", __FILE__, __LINE__ + 1 |
#enum_attr?(name) ⇒ Boolean
True if the given symbol maps to an enum-backed attribute
136 137 138 139 |
# File 'lib/iron/enum/attr_support.rb', line 136 def enum_attr?(name) return false unless @enum_attrs @enum_attrs.key?(name) end |
#enum_for_attr(name) ⇒ Object
Gets the enum class for a given attribute, or nil for none
142 143 144 145 |
# File 'lib/iron/enum/attr_support.rb', line 142 def enum_for_attr(name) return nil unless @enum_attrs @enum_attrs[name] end |