我有我的rails应用程序并试图通过添加一个名为cancancan的gem制作的方法来添加权限。所以下面有两种方法。
def find_review
@review = Review.find(params[:id])
end
def authorize_user!
unless can? :manage, @review
redirect_to product_path(@review.product)
end
end
有两种情况。案例1:调用destroy内部的方法动作
def destroy
find_review
authorize!
@product = @review.product
@reviews = @product.reviews
@review.destroy
end
和案例2:使用before_action方法调用方法
before_action :find_review, :authorize!, only: [:destroy]
def destroy
@product = @review.product
@reviews = @product.reviews
@review.destroy
redirect_to product_path(@product), notice: 'Review is deleted'
end
我使用before_action(案例2)甚至在调用操作之前重定向未经授权的用户,这样才有意义。我想知道的是在案例1中,为什么授权方法在销毁审核之前不会中断和重定向用户?它实际上重定向,但删除审查后。但我认为红宝石是同步的..
正如其他人所说,你的authorize!
不会中断请求,只会添加一个标题,然后继续进行破坏和诸如此类的东西。从嵌套方法调用中断流的一种很好的可靠方法是引发异常。像这样的东西:
class ApplicationController
NotAuthorizedError = Class.new(StandardError)
rescue_from NotAuthorizedError do
redirect_to root_path
end
end
class ReviewsController < ApplicationController
def authorize!
unless can?(:manage, @review)
fail NotAuthorizedError
end
end
def destroy
find_review
authorize! # if user is not authorized, the code below won't run
# because of the exception
@product = @review.product
@reviews = @product.reviews
@review.destroy
end
end
你可以整合cancan,because it does include an exception-raising authorize!
。你应该能够做到这一点:
def destroy
find_review
authorize! :manage, @review # can raise CanCan::AccessDenied
@product = @review.product
@reviews = @product.reviews
@review.destroy
end
或更好
load_and_authorize_resource
def destroy
@product = @review.product
@reviews = @product.reviews
@review.destroy
end
在案例1中,您需要在重定向到停止执行时从方法中使用return
,并使用ActionController::Metal#performed?来测试重定向是否已经过时:
def authorize_user!
unless can? :manage, @review
redirect_to product_path(@review.product) and return
end
end
def destroy
find_review
authorize!; return if performed?
@product = @review.product
@reviews = @product.reviews
@review.destroy
end
没有“异步行为”。 redirect_to
实际上只为响应对象添加了适当的头,它不会停止执行删除请求。
在情况1中,您需要在执行重定向到停止执行时从方法返回
return redirect_to product_path(@review.product)
在案例2中,您必须在授权方法中进行一些更改。
场景1.对于特定用户角色,根本无法管理Review模型
unless can?(:manage, Review)
redirect_to product_path(@review.product)
end
用模型名称替换实例变量
方案2,某些特定角色的用户可以管理审核,但某些角色的其他用户无法管理审核。
在这种情况下,您需要在调用can函数之前加载review对象
def authorize_user!
find_review
unless can?( :manage, @review)
redirect_to product_path(@review.product)
end
end
我想我的回答会对你有所帮助。