Rails 6 搭配 Pundit 时处理缺失记录的最优/改进方案是什么
方案1:全局异常拦截(推荐)
直接在 ApplicationController 中统一捕获两类预期异常,彻底消除每个方法的重复错误处理逻辑:
class ApplicationController < ActionController::Base # 保留你原有Pundit配置 after_action :verify_authorized, except: :index # 可选Pundit官方推荐配置 after_action :verify_policy_scoped, only: :index # 统一处理记录不存在错误 rescue_from ActiveRecord::RecordNotFound do redirect_to missing_record_path, status: :not_found end # 统一处理Pundit鉴权失败错误 rescue_from Pundit::NotAuthorizedError do |e| if e.record.nil? redirect_to missing_record_path, status: :not_found else redirect_back fallback_location: root_path, notice: 'You are not authorised to view this record.' end end end
改造后你的业务控制器方法不需要加任何rescue逻辑,只需要保留原有 authorize @record 调用即可,完全兼容 after_action 的鉴权校验规则,因为只要调用过 authorize 无论是否抛出异常,Pundit都会标记为已完成鉴权。
如果不需要这类预期内的错误上报到Bugsnag,可以在Bugsnag的忽略规则中加入 ActiveRecord::RecordNotFound 和符合条件的 Pundit::NotAuthorizedError 即可。
方案2:封装公共鉴权辅助方法
如果需要更灵活的自定义逻辑,可以封装通用方法复用:
# ApplicationController中定义 def safe_authorize(record) authorize record rescue Pundit::NotAuthorizedError if record.nil? redirect_to missing_record_path and return false else redirect_back fallback_location: root_path, notice: 'You are not authorised to view this record.' and return false end true end
业务方法使用方式:
def method_name return unless safe_authorize(@record) # 后续业务代码 end
额外优化建议
你可以把单条记录查询逻辑封装到 before_action 中:
before_action :find_record, only: [:show, :edit, :update, :destroy] def find_record @record = Record.find(params[:id]) end
记录不存在时会直接抛出 ActiveRecord::RecordNotFound 被全局拦截器处理,不需要走到鉴权步骤,更符合Rails开发约定。另外Rails 5+已经废弃 redirect_to :back 用法,建议替换为 redirect_back fallback_location: xxx 避免无Referer请求时报错。
内容的提问来源于stack exchange,提问作者Ben Richardson
相关产品推荐
相关产品推荐

