Reputation: 1784
I'm just learning ruby on rails and I have a table of user roles (Owner, Admin, and User). There are going to be places in the code where I need to check the user's role and show different options. Does anyone know how to do this without resorting to magic numbers or other ugly methods?
In ASP.Net web apps I've worked on I've seen this done through the use of enumerated types:
public enum UserRole { Owner = 1, Admin = 2, User = 3 }
// ...
if (user.Role == UserRole.Admin)
// Show special admin options
Each different role in the database is reflected as an enumerated type with a value set to the ID of that role in the database. That doesn't seem like a very good solution because it depends on knowledge of database that may change. Even if it is the proper way to handle something like this, I don't know how to use enumerated types in rails.
I would appreciate any insight into this matter.
Upvotes: 26
Views: 16379
Reputation: 2798
Could the functionality added in Rails 4.1, be what you are looking for ?
http://coherence.io/blog/2013/12/17/whats-new-in-rails-4-1.html
Copy from blog post:
class Bug < ActiveRecord::Base
# Relevant schema change looks like this:
#
# create_table :bugs do |t|
# t.column :status, :integer, default: 0 # defaults to the first value (i.e. :unverified)
# end
enum status: [ :unverified, :confirmed, :assigned, :in_progress, :resolved, :rejected, :reopened ]
...
Bug.resolved # => a scope to find all resolved bugs
bug.resolved? # => check if bug has the status resolved
bug.resolved! # => update! the bug with status set to resolved
bug.status # => a string describing the bug's status
bug.status = :resolved # => set the bug's status to resolved
Upvotes: 13
Reputation: 51717
This seems like a really good case for using my classy_enum gem. It essentially allows you to define a fixed set of options, where each one is a class with behavior and properties specific to it. It helps cut down on all the conditional logic that tends to get scattered throughout the application.
For example, If you are doing things like this:
class User < ActiveRecord::Base
def options
if user.is_admin?
[...admin options...]
else
[...non admin options...]
end
end
end
Then calling as: user.options
somewhere else...
classy_enum allows you to move that logic to a separate place and have the same functionality with no conditional logic:
class User < ActiveRecord::Base
classy_enum_attr :role
delegate :options, :to => :role
end
The README has a working example and describes the gem in detail.
Upvotes: 4
Reputation: 45941
Just starting to learn Rails (from C#), and had this exact same question. It seems that Rails doesn't really have enums because the philosophy is different. I would use tons of enums to try to organize all the details in a C# project, but maybe since Rails handles so much for you they aren't that important. It's not really an answer, just an observation.
Upvotes: 2
Reputation: 86
There's a enum plugin on rubyforge so you do:
t.column :severity, :enum, :limit => [:low, :medium, :high, :critical]
It's pretty ugly to use :limit
attribute to pass parameters, but it's a more standardized way.
To install just do:
script/plugin install svn://rubyforge.org/var/svn/enum-column/plugins/enum-column
it currenctly works with Rails 2.2.2 or later. Rubyforge link: www.rubyforge.org/projects/enum-column/
Upvotes: 0
Reputation: 10876
I prefer to use the aptly named Authorization plugin for situations like this.
This will let you
permit "role"
to restrict access to roles, and
permit? "role"
to simply test for access. Both of these delegate to User#has_role?(role)
.
Don't feel like you have to use their ObjectRoles
implementation. You can use the Hardwired
roles and then implement your own User#has_role?(role)
method to use your existing schema.
Upvotes: 2
Reputation: 5767
Ruby itself does not have an enumerated type, but this site shows a method http://www.rubyfleebie.com/enumerations-and-ruby/
You could make something like this in your User model:
#constants
OWNER = 1
ADMIN = 2
USER = 3
def is_owner?
self.role == OWNER
end
def is_admin?
self.role == ADMIN
end
def is_user?
self.role == USER
end
Upvotes: 26