-
Notifications
You must be signed in to change notification settings - Fork 2.3k
CanCanCan
Rails Admin is fully compatible with CanCanCan (previously cancan), an authorization framework to limit which actions a user can perform on each model.
If you haven't already, setup CanCanCan by adding it to your Gemfile and running the bundle
command.
gem "cancancan"
Next, run the generator to create an Ability class. This is where authorization rules are defined.
rails g cancan:ability
To use it with Rails Admin, add this to an initializer.
# in config/initializers/rails_admin.rb
RailsAdmin.config do |config|
config.authorize_with :cancan #TODO add cancancan to rails_admin config
end
At this point, all authorization will fail and no one will be able to access the admin pages. To grant access, add this to Ability#initialize
. You must also grant access to the dashboard
, or the login will fail there.
can :access, :rails_admin # grant access to rails_admin
can :dashboard # grant access to the dashboard
Then, you will need to grant access on each of the models. Here's a complete example of an Ability
class which defines different permissions depending upon the user's role.
class Ability
include CanCan::Ability
def initialize(user)
can :read, :all # allow everyone to read everything
if user && user.admin?
can :access, :rails_admin # only allow admin users to access Rails Admin
can :dashboard # allow access to dashboard
if user.role? :superadmin
can :manage, :all # allow superadmins to do anything
elsif user.role? :manager
can :manage, [User, Product] # allow managers to do anything to products and users
elsif user.role? :sales
can :update, Product, :hidden => false # allow sales to only update visible products
end
end
end
end
How you define the user roles is completely up to you. See the CanCanCan Documentation for more information.
If you use Cancan in your project, there are chances that abilities for RailsAdmin will conflict with your project ones. In that case, you will want to define a specific Ability class for admin section (e.g. AdminAbility
).
You just have to add your admin ability class as a second parameter to authorize_with
:
# in config/initializers/rails_admin.rb
RailsAdmin.config do |config|
config.authorize_with :cancan, AdminAbility
end
With AdminAbility
:
# in models/admin_ability.rb
class AdminAbility
include CanCan::Ability
def initialize(user)
if user && user.admin?
can :access, :rails_admin
can :manage, :all
end
end
end
If the user authorization fails, a CanCan::AccessDenied exception will be raised. You can catch this and modify its behavior in the ApplicationController.
class ApplicationController < ActionController::Base
rescue_from CanCan::AccessDenied do |exception|
redirect_to main_app.root_path, :alert => exception.message
end
end
Also make sure RailsAdmin is inheriting from ApplicationController:
# in config/initializers/rails_admin.rb
config.parent_controller = 'ApplicationController'
Remove check_authorization
from app/controllers/application_controller.rb, use load_and_authorize_resource
on every controllers instead.
Or use the :unless
option to test against rails_admin_controller?
.
Each action in RailsAdmin checks for authorization if adapter is present. Usually the name of the action gives the name of the verb used.
Here are the checks used by default in RailsAdmin:
# Always performed
can :access, :rails_admin # needed to access RailsAdmin
# Performed checks for `root` level actions:
can :dashboard # dashboard access
# Performed checks for `collection` scoped actions:
can :index, Model # included in :read
can :new, Model # included in :create
can :export, Model
can :history, Model # for HistoryIndex
can :destroy, Model # for BulkDelete
# Performed checks for `member` scoped actions:
can :show, Model, object # included in :read
can :edit, Model, object # included in :update
can :destroy, Model, object # for Delete
can :history, Model, object # for HistoryShow
can :show_in_app, Model, object