如何通过在Ruby中传递块来拯救?

时间:2014-11-27 11:26:45

标签: ruby-on-rails ruby ruby-on-rails-4

我在我的一个控制器中定义了自己的方法authorize_user,如下:

    def authorize_user
      if !((current_user.has_role? :admin, @operator) || (current_user.has_role? :super_admin))
        raise CanCan::AccessDenied
      end
    end

我想从CanCan异常(或任何其他例外)中解救。我在我的应用程序中使用了Rolify。如何使用自定义消息拯救并重定向到我的应用的root_url

我尝试了以下选项,但没有一个可以使用:

尝试1:

rescue CanCan::AccessDenied do |exception|
    redirect_to root_url, :alert => exception.message
end

在这种情况下出错:syntax error, unexpected keyword_do, expecting '('

尝试2:

rescue CanCan::AccessDenied
  redirect_to root_url, :alert => "Unauthorized Access"

在这种情况下出错:Render and/or redirect were called multiple times in this action

如何解决此问题?


这是我的控制器代码:

class CabsController < ApplicationController
  before_action :set_cab, only: [:show, :edit, :update, :destroy]
  before_action :authenticate_user!
  after_action :authorize_user

 # Some basic CRUD actions

 private

    def set_cab
      @cab = Cab.find(params[:id])
      @operator = Operator.find(params[:operator_id])
    end


    def cab_params
      params.require(:cab).permit(:category, :number)
    end

    def authorize_user
      if !((current_user.has_role? :admin, @operator) || (current_user.has_role? :super_admin))
        raise CanCan::AccessDenied
      end
    end
end

3 个答案:

答案 0 :(得分:6)

我认为您可以尝试rescue_from方法。

例如,您的ApplicationController看起来像这样:

class ApplicationController < ActionController::Base
  rescue_from CanCan::AccessDenied, with: :not_authorized

  #other stuff      

  private
  def not_authorized
    redirect_to root_url, alert: "Unauthorized Access"
  end
end

由于问题已使用更多代码进行更新,因此以下是其他信息:

一些建议:

  • 也可以:authorize_user成为before_action。这样,即使不允许用户执行操作,您也不必担心代码在操作中运行。
  • 您可能还需要添加与:only相同的:set_cab选项,因为您使用@operator实例变量。
  • 最后,个人代码风格偏好是我将if !更改为unless以增加阅读流量。

答案 1 :(得分:0)

尝试redirect_to(...) and return

答案 2 :(得分:0)

同意 Jakob W 我想指出,授权(和身份验证)必须仅在行动之前执行。当DB事务,读/写文件系统等已经完成时,任何授权和异常提升的目的是什么?

使用before_actionRender and/or redirect were called multiple times in this action没有问题 - 只有一个重定向 - 在控制器方法调用之前的异常处理中。

所以,我推荐下一个代码(更新 Jakob W&#39; 样本):

class CabsController < ApplicationController
  #...
  before_action :authorize_user

  private
    #...
    def authorize_user
      if !((current_user.has_role? :admin, @operator) || (current_user.has_role? :super_admin))
        raise CanCan::AccessDenied
      end
    end
end


class ApplicationController < ActionController::Base
  rescue_from CanCan::AccessDenied, with: :not_authorized

  #other stuff      

  private
  def not_authorized
    redirect_to(request.referrer || root_path), alert: "Unauthorized Access"
  end
end

我可以推荐另一个授权宝石吗?我认为这个是灵活且易于使用的 - 专家(https://github.com/elabs/pundit)。 github上的页面提供了一些有关授权的有用提示。