It seems that a lot of the Rails applications I’ve been working on have a User model that has a many-to-many relation with a Role model, so that users can have a role like “admin” or “manager”, or even multiple roles. Along with this comes the necessity to conditionally show things in views. Recently I’ve started moving away from having explicit @current_user.has_role(”whatever”) calls in the views, to some code in the application_helper.rb file:
module ApplicationHelper
def admin_only(&block)
role_only("administrator", &block)
end
def manager_only(&block)
role_only("manager", &block)
end
private
def role_only(rolename, &block)
if not @current_user.blank? and @current_user.has_role?(rolename)
block.call
end
end
end
Now in views I can easily mark off sections that should be displayed to only one user type:
<% admin_only do %> <!-- administrator content goes here --> <% end %> <% manager_only do %> <!-- manager content goes here --> <% end %>
It would be easy to extend the role_only method to take an array of roles and check for membership in any of them, but I haven’t had need of that yet.
Hat tip to Aaron Longwell for introducing me to this technique.


2 comments
Comments feed for this article
October 31, 2008 at 10:30 am
John
Perfect, I had hacked something together to handle manager / employee views but this makes it a bit simpler. I’ll give it a try tonight.
November 6, 2008 at 11:04 am
Bill Davenport
Nice solution. I’ve often wondered how to clean up the front end code and make anything on the View appear(or not appear) based on a role and still have nice clean code.
While I like putting all of your code in once place, I really don’t like to modify production code every time there’s a need to protect something.
One idea that I’ve worked with is URL parsing and storing the role/permission in the DB. It’s very flexible.
I store the permission utilizing the rails convention of controller and action. Storing the path in the DB and assign it to a role. Then assign that role to a user. Now I can protect create, edit, update, delete per controller with very little code.
On the front end I say and my library will parse the path and check if they have that permission. While this abstracts some of the conditional logic on the front end but doesn’t totally eliminate it. It does offer some very nice fine grained control.