haz_enum
haz_enum is a ActiveRecord extension to allow associations to enumerations.
Installation
haz_enum is hostet on rubygems.org, so yoou can just do
gem install haz_enum
or if you use bundler, just add the following line to your Gemfile:
gem "haz_enum"
Example with renum
renum is a perfect library for enumerations in ruby (see github.com/duelinmarkers/renum). Here is a simple renum definition:
enum :Roles do
Admin()
Supervisor()
ContentManager()
end
in your AR-model you can now write
class User < ActiveRecord
has_enum :role
end
what you need is a column in your db named role with type string.
user = User.create(:role => Roles::Admin)
user.has_role?(Roles::Admin) => true
user.has_role?(Roles::Supervisor) => false
The example above realizes one role per user. But what if you want to have multiple Roles per user? Just change has_enum to has_set and rename the column to roles:
class User < ActiveRecord
has_set :roles
end
user = User.create(:roles => Roles::Admin)
user.has_role?(Roles::Admin) => true
user.has_role?(Roles::Supervisor) => false
or
user = User.create(:roles => [Roles::Admin, Roles::Supervisor])
user.has_role?(Roles::Admin) => true
user.has_role?(Roles::Supervisor) => true
now roles behaves just like an array, so you can also do
user = User.create(:roles => Roles::Admin)
user.roles << Roles::Supervisor
user.has_role?(Roles::Admin) => true
user.has_role?(Roles::Supervisor) => true
Using bitfields
If you have an enum with many possible values you can switch from :yml to field_type :bitfield.
class User < ActiveRecord
has_set :roles, :field_type => :bitfield
end
Your db-column has to be an integer for field_type bitfield. If you use mysql with int(11) you are able to have up to 64 different values in your enumeration.
You do not need renum
…but it really makes sense to use this library. If you really do not want to use it you have to implement against an interface. Here is a simple ruby module example to get the same results as above for has_enum:
module Roles
class Admin; def self.name; "Admin"; end; end
class Supervisor; def self.name; "Supervisor"; end; end
class ContentManager; def self.name; "ContentManager"; end; end
end
You cannot use this for has_set and field_type :yml since you cannot dump anonymous classes. But you can use field_type :bitfield. Then your class could look something like that:
module Roles
class Admin
def self.bitfield_index; 1; end
end
class Supervisor
def self.bitfield_index; 2; end
end
class ContentManager
def self.bitfield_index; 3; end
end
class <<self
def values
Roles.constants.collect { |c| Roles.const_get(c) }
end
end
end
As you can see, your classes have to respond to bitfield_index and your wrapping module has to respond to values and return all available classes. So now you could do:
class User < ActiveRecord
has_enum :role, :field_type => :bitfield
end
Note on Patches/Pull Requests
-
Fork the project.
-
Make your feature addition or bug fix.
-
Add tests for it. This is important so I don’t break it in a future version unintentionally.
-
Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
-
Send me a pull request. Bonus points for topic branches.
Copyright
Copyright © 2010 Galaxy Cats IT Consulting GmbH. See LICENSE for details.