Authorize: Action-level Role and Permissions handling for Rails
Credit: This plugin expands on the original code and ideas of Chris Scharf.
This plugin provides role and permissions handling for Rails applications. It is designed for an escalating permissions
system, where each higher role contains all of the permissions of the roles below it. If you are seeking a many-to-many
type of role/permissions solution, this is not it.
Here’s all you need to know to get started:
- Make sure you have a #role column of type Integer in your “users” table
script/plugin install git://github.com/rpheath/authorize.git
- Open up the model that manages your users and add
include Authorize::Rolesat the top
- Redefine the constants in
Authorize::Levels(authorize/lib/authorize/levels.rb) to make sense (these
constants will be used to generate methods on the fly, so use proper naming :-)
Once you’ve done those initial steps, you can define permissions in your controllers like so:
class PostsController < ActionController::Base permissions do author :new, :create editor :edit, :update publisher :destroy end # ... end
You define the lowest level of permission for a list of actions. So assuming that an editor is higher up than an author,
an editor would have access to new, create, edit, update, whereas an author can only access new and create. Make sense?
Keep in mind, the available methods used in the permissions block (i.e. author, editor, etc) map to the constants that
you have defined in
Authorize::Levels. Meaning, the above code would assume you had:
module Authorize module Levels AUTHOR = 0 unless const_defined?(:AUTHOR) EDITOR = 1 unless const_defined?(:EDITOR) PUBLISHER = 2 unless const_defined?(:PUBLISHER) end end
And having a
PUBLIC_USER constant would build a
public_user permissions method, as expected, so underscores are handled properly.
This plugin will generate some named_scope’s for you based on the permission levels you defined in
Authorize::Levels. Sticking with our
example from above, we’ll assume you have three: AUTHOR, EDITOR, PUBLISHER. This will allow you to do:
User.authors # => all users having the at least an author role User.editors # => all users having at least an editor role
Now, since the permissions are setup to build upon the previous one, calling
User.authors will return not only all of the users having the
author role, but also all users having a role above that (since they also have “author” permissions). I realize this may not be the most
desireable approach in all cases, so you can pass “true” to any of the named_scope’s to return the users having exactly that role.
User.authors(true) # => all users having exactly the author role User.editors(true) # => all users having exactly the editor role
For each level of permission defined, the authorize plugin will automatically generate a block helper for you. This let’s you do:
<% editor do %> (editor only content) <% end %>
In the above example, it will only yield if the current user has editor permissions or above. Useful for keeping your views clean.
If a user tries to access an action that he/she does not have access to, a protected
invalid_permissions method would get called.
By default this method will display a warning and redirect to the
root_path. However, if you want some other behavior, just redefine this
method in your application controller.
Choosing a Role
There’s built-in support for drop down menus. Assuming you included the module into a
User class, you would call:
false as a parameter to remove the default
-- Choose Role -- option. Or you can pass
:default_text => '--' to set your own. For good measure, you could wrap this up in a helper called
role_options or something.
It seems that most of my applications involving these types of permissions involve an “inactive” state for the user.
Essentially, this is nothing more than a role with no permission to do anything, and I feel should be treated as such.
Browse through the code to see how the inactive stuff works, but really it’s just like another role, and you have
inactive? methods available automatically.
If you look in
Authorize::Levels you can see that there’s
self.lowest methods. These are useful for defining
what you would like your default permission to be (most cases, inactive) and your lowest level of permission. If you are not using
the inactive state, then you typically would want the default and lowest to be the same, but I’ll leave that up to you.
Here’s an example usecase for the
class User < ActiveRecord::Base before_create :set_default_role private def set_default_role self[:role] = Authorize::Levels.default end end
The Super User
In a lot of cases, you want to have that user who is above all and permissions are simply irrelevant. The plugin will react to
super_user? method, giving them permissions to do anything and everything. If you want to use it, just add a boolean “super_user”
flag to your “users” table, and
ActiveRecord will automatically provide a
super_user? method. The plugin checks if the user
responds to the super user stuff, so if you don’t want to use it, you don’t have to anything.
Copyright © 2009 Ryan Heath and Chris Scharf, released under the MIT license