Skip to content

Instantly share code, notes, and snippets.

@jastkand
Forked from watson/ability.rb
Created September 22, 2012 09:42
Show Gist options
  • Save jastkand/3765692 to your computer and use it in GitHub Desktop.
Save jastkand/3765692 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 ||= AdminUser.new
case user.role
when "admin"
can :manage, :all
when "school"
can :manage, Schedule, :team => { :school_id => user.school_id }
# the list of 'cans' of the user with school role
end
end
end
# lib/activeadmin_cancan.rb
# Integration with CanCan
module ActiveAdminCanCan
def active_admin_collection
super.accessible_by current_ability
end
def resource
resource = super
authorize! permission, resource
resource
end
private
def permission
case action_name
when "show"
:read
when "new", "create"
:create
when "edit"
:update
else
action_name.to_sym
end
end
end
# config/initializers/activeadmin_filter_conditions.rb
# This monkeypatch allows to use conditions if filters like
#
# filter :school, :as => :select, :collection => proc { School.all }, :if => proc { can? :manage, AdminUser }
#
# this filter will be shown only for roles who can manage AdminUser model
module ActiveAdmin
module Filters
class FormBuilder < ::ActiveAdmin::FormBuilder
def filter(method, options = {})
return "" if method.blank?
options[:as] ||= default_input_type(method)
return "" if (options[:if].is_a?(Proc) && !template.instance_eval(&options[:if])) || (options[:unless].is_a?(Proc) && template.instance_eval(&options[:unless]))
return "" unless options[:as]
content = input(method, options)
form_buffers.last << content.html_safe if content
end
end
end
end
# config/application.rb
# Set up config.autoload_paths parameter like this:
#
# config.autoload_paths += %W(#{config.root}/lib)
#
# Don't forget to remove comment symbol
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
rescue_from CanCan::AccessDenied do |exception|
redirect_to admin_dashboard_path, :alert => exception.message
end
def current_ability
@current_ability ||= Ability.new(current_admin_user)
end
`
``# the other source of you application controller
end
# app/admin/foobars.rb
ActiveAdmin.register Schedule do
# Filter with condition
filter :school, :as => :select, :collection => proc { School.all }, :if => proc { can? :manage, AdminUser }
# This will authorize the Schedule class
controller do
authorize_resource
include ActiveAdminCanCan
def scoped_collection
end_of_association_chain.includes(:team)
end
end
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(school admin)
# 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment