Skip to content

Instantly share code, notes, and snippets.

@watson
Created October 5, 2011 09:50
Show Gist options
  • Star 75 You must be signed in to star a gist
  • Fork 16 You must be signed in to fork a gist
  • Save watson/1264060 to your computer and use it in GitHub Desktop.
Save watson/1264060 to your computer and use it in GitHub Desktop.
Active Admin CanCan integration with shared front/backend User model and multi-level autherization
# app/models/ability.rb
# All front end users are authorized using this class
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new
can :read, :all
end
end
# config/initializers/active_admin.rb
ActiveAdmin.setup do |config|
# You don't need to modify any settings here to get CanCan to work
# Just remember to add CanCan to your Gemfile
# ...
end
# Below the ActiveAdmin.setup block, I've opened up the ActiveAdmin::ResourceController
# and modified the current_ability method to use a special AdminAbility class.
# Technically you can put this code almost anywere, but I've added it here because
# I think it belongs together with the other Active Admin initializer code.
ActiveAdmin::ResourceController.class_eval do
protected
def current_ability
@current_ability ||= AdminAbility.new(current_user)
end
end
# app/models/admin_ability.rb
# All back end users (i.e. Active Admin users) are authorized using this class
class AdminAbility
include CanCan::Ability
def initialize(user)
user ||= User.new
# We operate with three role levels:
# - Editor
# - Moderator
# - Manager
# An editor can do the following:
can :manage, Foobar
can :read, SomeOtherModel
# A moderator can do the following:
if user.role?('moderator')
can :manage, SomeOtherModel
end
# A manager can do the following:
if user.role?('manager')
can :manage, SomeThirdModel
end
end
end
# app/admin/foobars.rb
ActiveAdmin.register Foobar do
# This will authorize the Foobar class
# The authorization is done using the AdminAbility class
controller.authorize_resource
end
# app/models/user.rb
class User < ActiveRecord::Base
# The order of the ROLES array is important!
# All privileges are inherited from left to right
ROLES = %w(editor moderator manager)
# Privileges are inherited between roles in the order specified in the ROLES
# array. E.g. A moderator can do the same as an editor + more.
#
# This method understands that and will therefore return true for moderator
# users even if you call `role?('editor')`.
def role?(base_role)
return false unless role # A user have a role attribute. If not set, the user does not have any roles.
ROLES.index(base_role.to_s) <= ROLES.index(role)
end
end
@amalagaura
Copy link

This is very helpful, but didn't you have to customize the routes.rb?

@watson
Copy link
Author

watson commented Jan 19, 2012

Sorry about the late reply - no I don't think I did. I have a customization, but that is just for using a login form. Don't think it matters in this case.

@stigi
Copy link

stigi commented Feb 25, 2012

I added config.before_filter :check_admin_role to ActiveAdmin.setup and implemented a filter like this inside ActiveAdmin::ResourceController.class_eval do

  def check_admin_role
    return if current_user.role?(:admin)
    flash[:notice] = "You need to be an admin to access this part of the application"
    redirect_to root_path
  end

@dlupu
Copy link

dlupu commented Mar 14, 2012

Thanks @stigi. Your solution is perfect for my needs !

@stigi
Copy link

stigi commented Mar 14, 2012

@dlupu: glad I could help. will think about how all the valuable information in this git can be presented better. don't remember how I found it in the first place ;)

@pedroassumpcao
Copy link

I think we need to use the current_admin_user in the active_admin initializer:

 def current_ability
   @current_ability ||= AdminAbility.new(current_admin_user)
 end

@amiel
Copy link

amiel commented Apr 28, 2012

@watson: Thanks, this is very helpful.

@imderek
Copy link

imderek commented Jun 20, 2012

Once again, very helpful. Thanks!

@yorch
Copy link

yorch commented Jul 27, 2012

Thanks @stigi, works great.. just a minor fix (rolify 3.1.0):

def check_admin_role
  return if current_user.has_role?(:admin)
  flash[:notice] = "You need to be an admin to access this part of the application"
  redirect_to root_path
end

@maxinuss
Copy link

maxinuss commented Oct 1, 2012

Hey guys, how can add a role to a User?

@mhuggins
Copy link

@maxinuss - You probably want to refer to this.

@developer88
Copy link

Thanks for your gist. I use it to create my own https://gist.github.com/developer88/5007569
Main difference is that i store permission in database.

@murtuzakz
Copy link

I tried the above code. My index page /admin/users, still shows me list of all users, Even though for the user that is logged in, I have given him ability to only manage users from his organization.
The permissions work fine for show and edit.
Can someone please help?

@xjyjp
Copy link

xjyjp commented Aug 12, 2015

I do not know why it is not updated, but nowadays it is recommended to simple the cancan gem with Active_Admin. Here is the link http://activeadmin.info/docs/13-authorization-adapter.html#using_the_cancan_adapter

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment