Skip to content
Simple role-based access control plugin for Rails controllers and views -- cloned from Mathew Abonyi's (mabs29) repo:
Find file
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.



Acknowledgements: I give all credit to Ezra and Technoweenie for their two plugins which
inspired the interface design and a lot of the code for this one.

SimpleAccessControl is a streamlined, intuitive authorisation system. It derives heavily from
acl_system2 and has made clear some problems which plagued me when first using it. Some
fixes to acl_system2's design:

      * a normal Rails syntax:
            access_rule 'admin', :only => :index
            access_rule '(moderator || admin)', :only => :new
      * error handling for helper methods (permit? bombed when current_user == nil)
      * one-line parser, easy to replace or alter
      * proper before_filter usage, meaning access rules are parsed only when needed
      * no overrideable default (which I found counter-intuitive in the end)

Also, it has two methods, access_control and permit?, for those moving from acl_system2.

But, let me stress, everyone likes a slightly different system, so this one may not be
your style. I find it synchronises very well with the interface of Acts as Authenticated (even
though I have modified it so much that it's now called Authenticated Cookie).


Create the following migration:

  create_table "roles", :force => true do |t|
    t.column "title", :string
  create_table "roles_users", :id => false, :force => true do |t|
    t.column "role_id", :integer
    t.column "user_id", :integer

In your User model, you must have:

  has_and_belongs_to_many :roles
In your Roles model, you must have:

  has_and_belongs_to_many :users

Your controllers must have the following two methods or variants of them:

  # Returns a User object
  def current_user

  # Returns true or false if a User object exists for this session
  def logged_in?
    @current_user.is_a? User


If you want to permit anonymous users without demanding that they are logged in, first you
must ensure that logged_in? returns true in all cases, otherwise permission will be denied.
The following approach should work:

1. Create the 'guest' and 'user' roles, e.g.:

  guest = Role.create(:title => 'guest')
  user = Role.create(:title => 'user')

2. In your registration/user creation area, ensure all real users have the 'user' role, e.g.:

  @user = User.create(params[:user])
  unless @user.roles.any? { |r| r.title == 'user' }
    @user.roles << Role.find_by_title('user')

[At this point you have two options: a real or virtual anonymous account]

First Approach: Real Anonymous User

  3a. Create an anonymous user, e.g.:

    @anonymous = User.create(:login => 'anonymous', :password => '*', :activated => true)

  4a. Add the role to the Anonymous user (in a migration or in script/console), e.g.:

    anonymous.roles << Role.find_by_title('guest')

  5a. In your ApplicationController, set unauthenticated users as 'anonymous', e.g.:

    before_filter :default_to_guest

    def default_to_guest
      self.current_user = User.find_by_login('anonymous', :include => :roles) unless logged_in?

Second Approach: Virtual Anonymous User

  3a. In your ApplicationController, create a virtual anonymous account if unauthenticated:

    before_filter :default_to_virtual_guest
    def default_to_virtual_guest
      self.current_user = self.anonymous_user unless logged_in?

    def anonymous_user
      anonymous = => 'anonymous', :name => 'Guest')
      anonymous.roles << => 'guest')


The plugin is automatically hooked into ActionController::Base.

In your controllers, add access rules like so:

  access_rule 'admin', :only => :destroy
  access_rule 'user || admin', :only => [:new, :create, :edit, :update]

Note the use of Ruby-style operators. These strings are real conditionals and should be treated as
such. Every grouping of non-operator characters will be considered a role title.

In your views, you can use the following:

  <% restrict_to 'admin || moderator' do %>
    <%= link_to "Admin Area", admin_area_url %>
  <% end %>

  <%= link_to("Admin Area", admin_area_url) if has_permission?('admin || moderator') %>

There are also transitional methods which help you move from acl_system2 to this plugin -- I do this
not to denegrate acl_system2 but because I did this for myself and decided to include it. The two
systems are rather similar.

Also, there are two callbacks, permission_granted and permission_denied, which may define in your
controllers to customise their response. For example:

  def permission_granted"[authentication] Permission granted to %s at %s for %s" %
      [(logged_in? ? current_user.login : 'guest'),, request.request_uri])
  def permission_denied"[authentication] Permission denied to %s at %s for %s" %
      [(logged_in? ? current_user.login : 'guest'),, request.request_uri])

That's it!

Something went wrong with that request. Please try again.