用cancancan 来构建权限管理系统 - tianlu1677/tianlu1677.github.io GitHub Wiki

这里的权限管理主要以cms_admin的权限管理做介绍 同时,注意这里使用的是device与cancancan

- 1.修改gemfile, 安装gem

gem 'device'
gem 'cancancan'

-2. 建立权限model

rails g cancan:ability

会生成以下文件 app/models/ability.rb以及以下代码

class Ability
  include CanCan::Ability

  def initialize(user)
  end
end

-3. 创建数据库,因为这里采用的是

Administrator ——n * m———— roles ——n * m———— permissions

class DeviseCreateAdministrators < ActiveRecord::Migration
  def change
    create_table(:administrators) do |t|

      t.string  :username
      t.string  :name
      t.string  :gender
      t.string  :mobile
      t.string  :phone
      t.string  :status
      t.boolean :admin

      ## Database authenticatable
      t.string :email,              null: false, default: ""
      t.string :encrypted_password, null: false, default: ""

      ## Recoverable
      t.string   :reset_password_token
      t.datetime :reset_password_sent_at

      ## Rememberable
      t.datetime :remember_created_at

      ## Trackable
      t.integer  :sign_in_count, default: 0, null: false
      t.datetime :current_sign_in_at
      t.datetime :last_sign_in_at
      t.string   :current_sign_in_ip
      t.string   :last_sign_in_ip

      ## Confirmable
      # t.string   :confirmation_token
      # t.datetime :confirmed_at
      # t.datetime :confirmation_sent_at
      # t.string   :unconfirmed_email # Only if using reconfirmable

      ## Lockable
      # t.integer  :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts
      # t.string   :unlock_token # Only if unlock strategy is :email or :both
      # t.datetime :locked_at


      t.timestamps
    end

    add_index :administrators, :email,                unique: true
    add_index :administrators, :reset_password_token, unique: true
  end

  create_table :roles do |t|
    t.string :name
    t.timestamps
  end

  create_table :administrators_roles, id: false do |t|
    t.belongs_to :administrator
    t.belongs_to :role
  end

  add_index :administrators_roles, [:administrator_id, :role_id]

  create_table :permissions do |t|
    t.string  :name
    t.string  :subject_name
    t.string  :subject_class
    t.integer :subject_id
    t.string  :action
    t.text    :desc

    t.timestamps
  end

  create_table :permissions_roles, id: false do |t|
    t.belongs_to :permission
    t.belongs_to :role
  end

  add_index :permissions_roles, [:permission_id, :role_id]
end

然后执行 rake db:migrate

-4. 修改model中的关联关系

用户

class Administrator < ActiveRecord::Base
   devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable
    has_and_belongs_to_many :roles
    accepts_nested_attributes_for :roles
end

角色

class Role < ActiveRecord::Base

  has_and_belongs_to_many :administrators
  has_and_belongs_to_many :permissions
  accepts_nested_attributes_for :permissions

  validates :name, presence: true

end

权限


class Permission < ActiveRecord::Base

  has_and_belongs_to_many :roles

end

-5. 编写controller

class AdministratorsController <  ResourceController
  has_scope :search , :only => [:index] , :type => :hash
  def my
    @administrator = current_administrator
    render "show"
  end

  private
  def permitted_params
    if params[:administrator].present? and params[:administrator][:password].blank?
      params.permit(:administrator => [:username, :email, :name, :admin, role_ids: [], :roles_attributes => [:name]])
    else
      params.permit(:administrator => [:username, :email, :name, :admin, :password, :password_confirmation, role_ids: [], :roles_attributes => [:name]])
    end
  end

  def attributes
    %w(email username name roles admin)
  end
end

class RolesController < ResourceController

  private
  def permitted_params
    params.permit(role: [:name, permission_ids: []])
  end

  def attributes
    %w(name)
  end

end

# -*- encoding : utf-8 -*-
class PermissionsController < ResourceController

  private

  def permitted_params
    params.permit(:subject_name, :name, :subject_class, :subject_class, :subject_id, :action, :desc)
  end

  def attributes
    [:subject_name, :name, :subject_class, :subject_id, :action, :desc]
  end

end

- 6. 编写views

参见 views/administrators views/roles

-7. 修改具体的权限分配,与步骤1做对比后

class Ability
  include CanCan::Ability

  def initialize(user)
    return unless user.present?
    can :manage, :all and return if user.admin?

    user.roles.each do |role|
      role.permissions.each do |permission|
        if permission.subject_id.nil?
          can permission.action.to_sym, permission.subject_class.constantize
        else
          can permission.action.to_sym, permission.subject_class.constantize, :id => permission.subject_id
        end
      end
    end
  end
end

-8. 在seed中初始化各个model的权限

['Administrator', 'Role', 'Permission',
 'User', 'Collection', 'LearningRecord', 'MicroSpecialtiesUser',
 'InstructiveCourse', 'OpenCourse', 'Instructor', 'Institution', 'Syllabus',
 'Certificate', 'CertificateBackground', 'CertificateInstructor', 'CertificateInstitution',
 'CertificateInstitutionsCertificate', 'CertificateInstructorsCertificate',
 'Evaluation', 'Article', 'Category', 'Tag',
 'Specialty', 'MicroSpecialty',
 'Feedback', 'Faq', 'CommonLog', 'Bug',
 'Score', 'ScoreLog',
 'School', 'Student',
 'Navigation', 'CoursesNavigation', 'Banner', 'News', 'Advertisement'].each do |model|
  {manage: '管理', read: '查看', create: '添加', update: '修改', destroy: '删除'}.each do |k, v|
    Permission.create_with(name: v,
                           desc: "#{I18n.t("activerecord.models.#{model.underscore}")}",
                           subject_name: I18n.t("activerecord.models.#{model.underscore}")
    ).find_or_create_by!(action: k.to_s,
                         subject_class: model,
                         subject_id: nil
    )
  end