Skip to content

Instantly share code, notes, and snippets.

@developer88
Last active March 19, 2016 20:18
Show Gist options
  • Save developer88/5007569 to your computer and use it in GitHub Desktop.
Save developer88/5007569 to your computer and use it in GitHub Desktop.
This is my gist that show how we can use CanCan with ActiveAdmin and store permissions in database.
# config/initializers/active_admin.rb
ActiveAdmin.setup do |config|
config.current_user_method = :current_user
config.authentication_method = :authenticate_user!
config.before_filter :admin_role_filter
end
# Adding all recource names to Permissions table after ActiveAdmin is loaded
ActiveAdmin.after_load do |app|
# check if Permission table exists
if ActiveRecord::Base.connection.table_exists? 'permissions'
app.namespaces.each do |name, namespace|
namespace.resources.each do |resource|
next if resource.class.name.demodulize == 'Page'
resource_name = resource.resource_class_name.demodulize.underscore
Permission.create(name: resource_name) unless Permission.where(:name => resource_name).any?
end
end
end
end
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
# restrict abilities to every user
cannot :manage, :all
cannot :read, :all
cannot :edit, :all
# check ability stored in database
if user.is? :admin
can do |action, subject_class, subject|
user.as_admin_can?(subject_class)
end
end
end
end
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
def admin_role_filter
unless current_user.is?(:admin)
return redirect_to root_url
end
end
end
# app/models/permissation.rb
class Permissation < ActiveRecord::Base
belongs_to :user
belongs_to :permission
end
# app/models/permission.rb
class Permission < ActiveRecord::Base
has_many :permissations
has_many :users, through: :permissations
end
# db/migrate/123456789_create_permissions_table.rb
class CreatePermissionsTable < ActiveRecord::Migration
def up
# Create table
create_table :permissations do |t|
t.integer :user_id
t.integer :permission_id
end
create_table :permissions do |t|
t.string :name
t.timestamps
end
# Create necessary permissions
%w{permission user}.each {|p| Permission.create(name: p)}
# By default give these permissions to everyone with 'admin' role
User.find_each(:batch_size => 5000) do |user|
next unless user.is? :admin
user.permissions << Permission.find_by_name('permission')
user.permissions << Permission.find_by_name('user')
user.save
end
end
def down
drop_table :permissions
drop_table :permissations
end
end
# app/models/user.rb
class User < ActiveRecord::Base
ROLES = %w[admin manager editor]
has_many :permissions, through: :permissations
accepts_nested_attributes_for :permissions
attr_accessible :permission_ids
# check user's permission for ActiveAdmin
def as_admin_can? obj
permissions.where(:name => obj.to_s.underscore).count > 0
end
def roles
ROLES.reject do |r|
((roles_mask || 0) & 2 ** ROLES.index(r)).zero?
end
end
def is?(role)
roles.include?(role.to_s)
end
end
# any ActiveAdmin Resource
# app/admin/users.rb
ActiveAdmin.register User do
controller.authorize_resource
menu :parent => proc{ I18n.t("active_admin.menu.users") }, :if => proc{ current_user.as_admin_can?(User) }
index do
if current_user.as_admin_can? 'permission'
column I18n.t("activerecord.models.permission") do |user|
user.permissions.collect {|p| p.name.camelize }.join(", ")
end
end
end
form do |f|
if current_user.as_admin_can? 'permission'
f.inputs I18n.t("activerecord.models.permission") do
f.input :permissions, :as => :check_boxes, :collection => f.object.permissions | Permission.all
end
end
f.actions
end
end
@vanderv
Copy link

vanderv commented Jul 2, 2013

Hi! Where you get role_mask?

  def roles
    ROLES.reject do |r|
      ((roles_mask || 0) & 2 ** ROLES.index(r)).zero?
    end
  end 

@cdesch
Copy link

cdesch commented Jan 9, 2014

Can you post a full working example App using this feature?

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