Welcome to the acl_system plugin for rails. This plugin is designed to give you a
flexible declarative way of protecting your various controller actions using roles.
It's made to sit on top of any authentication framework that follows a few conventions.
You will need to have a current_user
method that returns the currently logged in user.
And you will need to make your User
or Account
model(or whatever you named it) have a
has_and_belongs_to_many :roles
. So you need a model called Role
that has a title
attribute.
Once these two things are satisfied you can use this plugin.
So lets take a look at the sugar you get from using this plugin. Keep in mind that the
!blacklist
part isn’t really necessary here. I was just showing it as an example of how
flexible the permissions string logic parser is.
class PostController < ApplicationController
before_filter :login_required, :except => [:list, :index]
access_control [:new, :create, :update, :edit] => '(admin | user | moderator)',
:delete => 'admin & (!moderator & !blacklist)'
Of course you can define them all separately if they differ at all.
class PostController < ApplicationController
before_filter :login_required, :except => [:list, :index]
access_control :new => '(admin | user | moderator) & !blacklist',
:create => 'admin & !blacklist',
:edit => '(admin | moderator) & !blacklist',
:update => '(admin | moderator) & !blacklist',
:delete => 'admin & (!moderator | !blacklist)'
And you can also use :DEFAULT
if you have a lot of actions that need the same permissions.
class PostController < ApplicationController
before_filter :login_required, :except => [:list, :index]
access_control :DEFAULT => '!guest'
[:new, :create, :update, :edit] => '(admin | user | moderator)',
:delete => 'admin & (!moderator & !blacklist)'
There are two callback methods you can use to define your own success and failure behaviours.
If you define permission_granted
and/or permission_denied
as protected methods in your controller you
can redirect or render and error page or whatever else you might want to do if access is allowed
or denied.
class PostController < ApplicationController
before_filter :login_required, :except => [:list, :index]
access_control :DEFAULT => '!guest'
[:new, :create, :update, :edit] => '(admin | user | moderator)',
:delete => 'admin & (!moderator & !blacklist)'
# the rest of your controller here
protected
def permission_denied
flash[:notice] = "You don't have privileges to access this action"
return redirect_to :action => 'denied'
end
def permission_granted
flash[:notice] = "Welcome to the secure area of foo.com!"
end
end
There is also a helper method that can be used in the view or controller. In the view its handy for conditional menus or stuff like that.
<% restrict_to "(admin | moderator) & !blacklist" do %>
<%= link_to "Admin & Moderator only link", :action =>'foo' %>
<% end %>
So the gist of it is that in the access_control
controller macro, you can assign
permission logic strings to actions in your controller. You supply a hash of
:action => 'permissions string'
pairs. Any action not in the list is left open to
any user. Any action with a logic string gets evaluated on each request to see if
the current user has the right role to access the action. The plugin has a small
recursive descent parser that evaluates the permission logic strings against the
current_user.roles
.
The way this works is that you have your User
model and a Role
model. User <= habtm => Role
.
So when an action that is access_control’ed gets requested the permission logic string
gets evaluated against the current_user.roles
. So a prerequisite of using this plugin
is that you add a Role
model with a title
attribute that has_and_belongs_to_many :user
models. And you need to have a current_user
method defined somewhere in your controllers
or user system. Luckily the acts_as_authenticated
plugin has the current_user
defined already.
So here is the schema of this application including the Post
model and the User
and Role
model plus the habtm join table:
ActiveRecord::Schema.define(:version => 3) do
create_table "posts", :force => true do |t|
t.column "title", :string, :limit => 40
t.column "body", :text
end
create_table "roles", :force => true do |t|
t.column "title", :string
end
create_table "roles_users", :id => false, :force => true do |t|
t.column "role_id", :integer
t.column "user_id", :integer
end
create_table "users", :force => true do |t|
t.column "login", :string, :limit => 40
t.column "email", :string, :limit => 100
t.column "crypted_password", :string, :limit => 40
t.column "salt", :string, :limit => 40
t.column "created_at", :datetime
t.column "updated_at", :datetime
end
end
And so thats pretty much it for now. You add the roles to the Role.title
attribute like admin,
moderator and blacklist like above. These can be anything you want them to be, roles, groups
or whatever. Then you can use as many nested parens and logic with & | !
as you want to
define your complex permissions for accessing your controller. Make sure that your access_control
gets called after the login_required
before filter because we assume that you are already
logged in if you made it this far and then we eval the permissions logic.
You will want to define these access_control in each controller that needs specific permissions.
unless you want to protect the same actions in all controllers, then you can put it in
application.rb
but I don't recommend it.