基于ActiveAdmin+CanCan+AASM的AJAX事件切换器:角色权限管控需求
刚好做过类似的需求,我来给你梳理一套完整的实现方案,完美结合ActiveAdmin、CanCan和AASM,实现基于角色权限的AJAX状态/事件切换功能:
核心目标
给不同角色的管理员提供AJAX化的AASM事件切换按钮,按钮的可见性与可用性完全由CanCan权限控制,操作后无需刷新页面即可更新状态
1. 先确保AASM模型配置正确
首先你的模型得有完整的AASM状态和事件定义,举个订单模型的例子:
class Order < ApplicationRecord include AASM aasm do state :pending, initial: true state :processed, :shipped, :cancelled event :process do transitions from: :pending, to: :processed end event :ship do transitions from: :processed, to: :shipped end event :cancel do transitions from: [:pending, :processed], to: :cancelled end end end
2. 用CanCan定义角色权限
在app/models/ability.rb里,给不同角色分配允许触发的事件权限,这里我们自定义trigger_event权限来做细粒度控制:
class Ability include CanCan::Ability def initialize(user) user ||= User.new # 处理未登录的访客情况 if user.admin? # 超级管理员拥有所有权限 can :manage, Order elsif user.processing_manager? # 处理岗管理员只能触发process事件 can :trigger_event, Order, event: [:process] can :read, Order elsif user.shipping_manager? # 发货岗管理员只能触发ship事件 can :trigger_event, Order, event: [:ship] can :read, Order elsif user.cancellation_manager? # 取消岗管理员只能触发cancel事件 can :trigger_event, Order, event: [:cancel] can :read, Order end end end
3. 在ActiveAdmin中配置AJAX切换列
接下来在ActiveAdmin的资源配置里,添加自定义列渲染AJAX按钮,同时加一个处理请求的动作:
ActiveAdmin.register Order do index do selectable_column id_column column :state do |order| # 用status_tag展示状态,自带样式 status_tag order.state, class: order.state end # 自定义动作列,渲染权限范围内的事件按钮 column :actions do |order| render partial: 'event_actions', locals: { order: order } end end # 添加处理AJAX请求的成员动作 member_action :trigger_event, method: :post do order = Order.find(params[:id]) event = params[:event].to_sym # 先判断用户权限 if can? :trigger_event, order, event: event if order.aasm.fire(event) # 成功后返回更新后的状态和动作按钮HTML render json: { state: order.state, actions: render_to_string(partial: 'event_actions', locals: { order: order }, formats: [:html]) } else render json: { error: order.errors.full_messages.join(', ') }, status: :unprocessable_entity end else render json: { error: '你没有权限执行此操作' }, status: :forbidden end end end
4. 提取事件按钮的部分视图
创建app/views/admin/orders/_event_actions.html.erb,把按钮渲染逻辑抽出来,方便AJAX更新复用:
<% # 只渲染当前用户有权限触发的事件按钮 %> <% order.aasm.events(permitted: true).each do |event| %> <% if can? :trigger_event, order, event: event.name %> <%= link_to event.name.humanize, trigger_event_admin_order_path(order, event: event.name), method: :post, remote: true, class: "button small #{event.name}" %> <% end %> <% end %>
5. 写JS处理AJAX响应
在app/assets/javascripts/admin/orders.js里添加AJAX成功/失败的处理逻辑,实现无刷新更新:
// 处理AJAX成功响应 $(document).on('ajax:success', '[data-remote=true]', function(e, data) { const $buttonCell = $(this).closest('td'); // 更新状态列的内容 $buttonCell.prev('td').html(`<span class="status_tag ${data.state}">${data.state.humanize()}</span>`); // 更新动作列的按钮 $buttonCell.html(data.actions); }); // 处理AJAX错误响应 $(document).on('ajax:error', '[data-remote=true]', function(e, xhr) { alert(xhr.responseJSON.error); });
6. 自定义状态标签样式(可选)
可以在ActiveAdmin的自定义CSS里给不同状态加颜色区分:
.status_tag.pending { background-color: #f1c40f; color: #fff; } .status_tag.processed { background-color: #3498db; color: #fff; } .status_tag.shipped { background-color: #2ecc71; color: #fff; } .status_tag.cancelled { background-color: #e74c3c; color: #fff; }
这样配置完成后,不同角色的管理员登录ActiveAdmin后,只会看到自己有权限触发的事件按钮,点击按钮通过AJAX完成状态切换,页面实时更新,完全符合你的需求。
内容的提问来源于stack exchange,提问作者alexey_the_cat
相关产品推荐
相关产品推荐

