haz_enum is a ActiveRecord extension to allow associations to enumerations.
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"
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
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.
…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
-
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 © 2010 Galaxy Cats IT Consulting GmbH. See LICENSE for details.