美文网首页
Ruby&Rails---ActiveAdmin、cancanc

Ruby&Rails---ActiveAdmin、cancanc

作者: HPD_黄霹雳 | 来源:发表于2018-12-02 17:20 被阅读0次

    role_core: https://github.com/rails-engine/role_core
    cancancan: https://github.com/CanCanCommunity/cancancan

    先说效果,后台有个Roles,是后台用户的角色。
    AdminUser就是后台用户,可分配某些角色。用户只能操作角色中赋予的功能

    图片.png

    安装gem

    # 后台界面
    gem 'activeadmin'
    gem 'devise'
    # 用户访问权限
    gem 'cancancan', '~> 2.0'
    # 用户访问角色权限配置
    gem 'role_core'
    

    activeadmin在之前的配置在之前的文章中讲过

    运行命令,生成abilitiy的文件

    rails g cancan:ability
    

    配置ActiveAdmin的权限管理适配器为cancancan,并且指定验证失败后的回调函数 access_denied

    config.authorization_adapter = ActiveAdmin::CanCanAdapter
    config.on_unauthorized_access = :access_denied
    

    在application_controller中配置access_denied函数

    class ApplicationController < ActionController::Base
      protect_from_forgery
    
      # cancanadapter,访问被拒绝后会回调这个方法
      def access_denied(exception)
        redirect_to admin_root_path, alert: exception.message
      end
    
      # cancanadapter,访问被拒绝后会回调这个方法,上面的那个方法无效,提示多了个参数(暂不知原因)
      def access_denied
        redirect_to admin_root_path, alert: "您没有权限访问!"
      end
    

    这里先只能访问Dashboard这个页面

    class Ability
      include CanCan::Ability
    
      def initialize(user)
        can :read, ActiveAdmin::Page, name: "Dashboard", namespace_name: "admin"
      end
    end
    
    

    到这里,cancancan和ActiveAdmin的集成已经完毕。至于权限代码还是得自己去实现。
    现在通过集成role_core来制定用户角色权限,之后就可以让运营自己玩了

    根据role_core的配置文档来运行命令


    图片.png

    这边是定义用户和角色是多对多的关系:


    图片.png

    role_core结合cancancan,在initializeres/role_core打开注释:

    require "role_core/contrib/can_can_can_permission"
    RoleCore.permission_class = RoleCore::CanCanCanPermission
    

    并且继续定义各个model的操作权限

    # frozen_string_literal: true
    
    # Be sure to restart your server when you modify this file.
    
    # For I18n, see `config/locales/role_core.en.yml` for details which followed the rule of ActiveRecord's I18n,
    # See <http://guides.rubyonrails.org/i18n.html#translations-for-active-record-models>.
    
    # Uncomment below if you want to integrate with CanCanCan
    #
    require "role_core/contrib/can_can_can_permission"
    RoleCore.permission_class = RoleCore::CanCanCanPermission
    
    RoleCore.permission_set_class.draw do
      # Define permissions for the application. For example:
      #
      #   permission :foo, default: true # `default: true` means grant to user by default
      #   permission :bar
      #
      # You can also group permissions by using `group`:
      #
      #   group :project do
      #     permission :create
      #     permission :destroy
      #     permission :update
      #     permission :read
      #     permission :read_public
      #
      #     # `group` supports nesting
      #     group :task do
      #       permission :create
      #       permission :destroy
      #       permission :update
      #       permission :read
      #     end
      #   end
      #
      # For CanCanCan integration, you can pass `model_name` for `group` or `permission`. For example:
      #
      #   group :project, model_name: "Project" do
      #     permission :create
      #     permission :destroy, model_name: 'Plan'
      #   end
      #
      # That will translate to CanCanCan's abilities (if user has these permissions),
      # the permission's name will be the action:
      #
      #   can :create, Project
      #   can :destroy, Plan
      #
      # You can pass `_priority` argument to `permission`
      #
      #   group :project, model_name: "Project" do
      #     permission :read_public,
      #     permission :read, _priority: 1
      #   end
      #
      # That will made 'read' prior than `read_public`.
      #
      # For CanCanCan's hash of conditions
      # (see https://github.com/CanCanCommunity/cancancan/wiki/Defining-Abilities#hash-of-conditions)
      # you can simply pass them as arguments for `permission` even with a block
      #
      #   group :task, model_name: "Task" do
      #     permission :read_public, is_public: true
      #     permission :update_my_own, action: :update, default: true do |user, task|
      #       task.user_id == user.id
      #     end
      #   end
      #
      # Although permission's name will be CanCanCan's action by default,
      # you can pass `action` argument to override it.
      #
      #   permission :read_public, action: :read, is_public: true
      #
      # For some reason, you won't interpret the permission to CanCanCan,
      # you can set `_callable: false` to `permission` or `group`
      #
      #   permission :read, _callable: false
      #
    
      group :admin do
    
        # group :user, model_name: "User" do
        #   permission :create
        #   permission :destroy
        #   permission :update
        #   permission :read
        #   permission :manage
        # end
        #
        # group :admin_user, model_name: "AdminUser" do
        #   permission :create
        #   permission :destroy
        #   permission :update
        #   permission :read
        #   permission :manage
        # end
    
        # 这里是简便的写法
        %w(user admin_user role).each do |item|
          group item.to_sym, model_name: "#{item.camelcase}" do
            permission :create
            permission :destroy
            permission :update
            permission :read
            permission :manage
          end
        end
      end
    
    end.finalize! # Call `finalize!` to freezing the definition, that's optional.
    
    

    在AdminUser中加入验证权限代码 computed_permissions

    class AdminUser < ApplicationRecord
      # Include default devise modules. Others available are:
      # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
      devise :database_authenticatable,
             :recoverable, :rememberable, :validatable
    
      # AdminUser与Role多对多
      has_many :role_assignments, dependent: :destroy
      has_many :roles, through: :role_assignments
    
      def computed_permissions
        roles.map(&:computed_permissions).reduce(RoleCore::ComputedPermissions.new, &:concat)
      end
    end
    
    

    在ability.rb中加入配置user.computed_permissions.call(self, user)

    class Ability
      include CanCan::Ability
    
      def initialize(user)
        user.computed_permissions.call(self, user)
        can :read, ActiveAdmin::Page, name: "Dashboard", namespace_name: "admin"
      end
    end
    
    

    ActiveAdmin中创建或更新的model和视图
    admin_users.rb

    ActiveAdmin.register AdminUser do
      permit_params :email, :password, :password_confirmation, role_ids: []
    
      index do
        selectable_column
        id_column
        column :email
        column :current_sign_in_at
        column :sign_in_count
        column :created_at
        actions
      end
    
      filter :email
      filter :current_sign_in_at
      filter :sign_in_count
      filter :created_at
    
      form partial: 'form'
    
    end
    

    admin_users/_form.html.erb

    <%= form_for([:admin, @admin_user], local: true) do |f| %>
      <% if @admin_user.errors.any? %>
        <article class="message is-danger">
          <div class="message-header">
            <p>
              <%= pluralize(@admin_user.errors.count, "error") %> prohibited this form from being saved:
            </p>
          </div>
          <div class="message-body">
            <% @admin_user.errors.full_messages.each do |message| %>
              <li><%= message %></li>
            <% end %>
          </div>
        </article>
      <% end %>
    
      <div class="field">
        <%= f.label :email, class: 'label' %>
        <p class="control">
          <%= f.text_field :email, id: :admin_user_email, class: 'input' %>
        </p>
      </div>
    
      <% if @admin_user.persisted? %>
        <div class="field">
          <%= f.label :roles, class: 'label' %>
          <p class="control">
            <%= f.collection_check_boxes :role_ids, Role.all, :id, :name do |m| %>
              <%= m.label class: 'checkbox' do %>
                <%= m.check_box class: 'checkbox' %>
                <%= m.text %>
              <% end %>
            <% end %>
          </p>
        </div>
      <% end %>
    
      <div class="field is-grouped">
        <p class="control">
          <%= f.submit class: 'button is-primary' %>
        </p>
        <p class="control">
          <%= link_to 'Back', url_for(:back), class: 'button is-link' %>
        </p>
      </div>
    <% end %>
    

    role.rb

    ActiveAdmin.register Role do
    
      form partial: 'form'
    
      # 注意:要写这个,不然创建不成功
      controller do
        def permitted_params
          params.permit!
        end
      end
    end
    

    roles/_form.html.erb

    <%= form_for([:admin, @role], local: true) do |f| %>
      <% if @role.errors.any? %>
        <article class="message is-danger">
          <div class="message-header">
            <p>
              <%= pluralize(@role.errors.count, "error") %> prohibited this form from being saved:
            </p>
          </div>
          <div class="message-body">
            <% @role.errors.full_messages.each do |message| %>
              <li><%= message %></li>
            <% end %>
          </div>
        </article>
      <% end %>
    
      <div class="field">
        <%= f.label :name, class: 'label' %>
        <p class="control">
          <%= f.text_field :name, id: :role_name, class: 'input', required: 'required' %>
        </p>
      </div>
    
      <%= render partial: "permissions", locals: {f: f, name: :permissions_attributes, permissions: @role.permissions} %>
    
      <div class="field is-grouped">
        <%= f.submit class: 'button is-primary' %>
        <%= link_to 'Back', url_for(:back), class: 'button is-link' %>
      </div>
    <% end %>
    
    

    roles/_permissions.html.erb

    <%= f.fields_for name, permissions do |ff| %>
      <% if permissions.class.attribute_names_for_inlining.any? %>
        <div class="field">
          <label class="label">
            <%= permissions.class.model_name.human %>
          </label>
    
          <p class="control">
            <% permissions.class.attribute_names_for_inlining.each do |permission| %>
              <%= ff.label permission, class: 'checkbox' do %>
                <%= ff.check_box permission, class: 'checkbox' %>
                <%= permissions.class.human_attribute_name(permission) %>
              <% end %>
            <% end %>
          </p>
        </div>
      <% end %>
    
      <% permissions.class.attribute_names_for_nesting.each do |permission| %>
        <%= render partial: "permissions", locals: {f: ff, name: permission, permissions: permissions.send(permission)} %>
      <% end %>
    <% end %>
    
    

    相关文章

      网友评论

          本文标题:Ruby&Rails---ActiveAdmin、cancanc

          本文链接:https://www.haomeiwen.com/subject/yqfjcqtx.html