一个中小型旅行社使用的一个简易 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 操作。