一个中小型旅行社使用的一个简易 CRM 系统。需要管理员能通过页面来对用户授权,颗粒精细到 action 即可。相关的 Gems 如下:
+ rails 3.2.8
+ devise 2.1.2
+ simple_form 2.0.2
+ cancan 1.6.8
思路: 使用 CanCan 实现基于数据库的授权。可以参考 Cancan 的 wiki 上这篇文章 [https://github.com/ryanb/cancan/wiki/Abilities-in-Database]。 用表 permissions 保存所有的权限,与 users 的关系是 has_and_belongs_to_many,在 Ability.rb 中处理一下 user.permissions 既可。
下面是具体实现的几个基本步骤: Gemfile 和 devise 的配置过程省略。
创建 model Permission
rails g model Permission action subject description
创建 has_had_belongs_to_mang
中间表。
rails g migration UsersHABTMPermissions
编辑 db/migrate/xx_users_habtm_permissions.rb
class UsersHabtmPermissions < ActiveRecord::Migration
def up
create_table :permissions_users, :id => false do |t|
t.references :permission
t.references :user
end
add_index :permissions_users, [:user_id, :permission_id]
add_index :permissions_users, [:permission_id, :user_id]
end
def down
drop_table :permissions_users
end
end
生成表
rake db:migrate
编辑 app/models/permission.rb,和 app/modles/user.rb,加入 habtm 关系
# app/models/user.rb
class User < ActiveRecord::Base
.
.
.
has_and_belongs_to_many :permissions
end
# app/models/permission.rb
class Permission < ActiveRecord::Base
attr_accessible :action, :description, :subject
has_and_belongs_to_many :users
end
创建 app/models/ability.rb
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new
## 指定超级用户
if user.id == 1
can :manage, :all
else
user.permissions.each do |p|
begin
action = p.action.to_sym
subject = begin
# RESTful Controllers
p.subject.camelize.constantize
rescue
# Non RESTful Controllers
p.subject.underscore.to_sym
end
can action, subject
rescue => e
Rails.logger.info "#{e}"
Rails.logger.info "#{subject}"
end
end
end
end
end
这样基本的步骤就完成了。然后我们手动把权限一条一条的加上去,并对用户授权
## 增加权限
Permission.create(:action => 'manage', :subject => 'user', :description => '用户管理')
Permission.create(:action => 'manage', :subject => 'hotel', :description => '酒店管理')
Permission.create(:action => 'read', :subject => 'hotel', :description => '酒店查看')
Permission.create(:action => 'index', :subject => 'hotel', :description => '酒店列表查看')
## 给用户授权
user = User.find 10
user.permissions = [...]
最后不要忘记在相应的 controller 中加入:
## 第一种情况 RESTful Controllers
load_and_authorize_resource
# 或者
authorize_resource
## 第二种情况 Non RESTful Controllers
authorize_resource :class => false
以上是本人在使用 Cancan 结合数据使用的简单实现,限于篇幅,用户授权和权限列表的页面操作就省略了,都是比较基础的 CRUD 操作。