【问题标题】:What's the "rails way" to access a resource in a controller's before_action在控制器的 before_action 中访问资源的“rails 方式”是什么
【发布时间】:2020-03-12 19:05:07
【问题描述】:

我正在使用 Pundit 来授权我的控制器中的操作。我的第一次尝试是在 after_action 挂钩中授权模型:

class CompaniesController < InheritedResources::Base
  after_action :authorize_company, except: :index

  def authorize_company
    authorize @company
  end

这让我可以使用定义@company 的默认控制器操作,这样我就不会两次访问数据库。但是,这对于破坏性操作是不利的,因为它不会在我已经搞砸数据库之后授权该操作。

所以,我改为使用before_action 钩子:

class CompaniesController < InheritedResources::Base
  before_action :authorize_company, except: :index

  def authorize_company
    @company = Company.find(params.require(:id))
    authorize @company
  end

现在,我不允许未经授权的人删除资源等...但是我两次访问数据库。无论如何访问@company而不访问数据库两次?

【问题讨论】:

    标签: ruby-on-rails controller pundit


    【解决方案1】:

    由于您要求使用“rails 方式”,因此您将在没有InheritedResources 的情况下在“普通旧导轨”中进行设置。

    class CompaniesController < ApplicationController
      before_action :authorize_company, except: [:new, :index]
    
      def new
        @company = authorize(Company.new)
      end
    
      def index
        @companies = policy_scope(Company)
      end
    
      # ...
    
      private
    
      def authorize_company
        @company = authorize(Company.find(params[:id]))
      end
    end
    

    如果你真的想要使用回调,你可以这样做:

    class CompaniesController < ApplicationController
      before_action :authorize_company, except: [:new, :index]
      before_action :authorize_companies, only: [:index]
      before_action :build_company, only: [:new]
    
      # ...
    
      private
    
      def authorize_company
        @company = authorize(Company.find(params[:id]))
      end
    
      def authorize_companies
        @companies = policy_scope(Company)
      end
    
      def build_companies
        @company = authorize(Company.new)
      end
    end
    

    是的,您可以编写一个包含三个代码分支的回调方法,但这具有较低的循环复杂度,并且每个方法只完成一项工作。

    【讨论】:

      【解决方案2】:

      如果模型存在,rails 控制器有一个resource,对于new 之类的操作,则有一个build_resource

      class CompaniesController < InheritedResources::Base
        before_action :authorize_company, except: :index
      
        private
      
          def authorize_company
            authorize resource
          rescue ActiveRecord::RecordNotFound
            authorize build_resource
          end
      end
      

      【讨论】:

      • 那更可能是 InheritedResources 的方法,而不是 Rails。
      • 不要这样做。 ActiveRecord::RecordNotFound 如果传递的 id 不是有效的 id 将引发,如果资源被删除并且有人关注旧链接,这将在您的应用程序中发生。您现在不是返回错误页面和 404,而是使用新的(空白)资源渲染显示页面,并且会得到大量的 nil 错误。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-09-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-08
      • 2014-05-21
      • 2012-02-10
      相关资源
      最近更新 更多