我以为ruby是同步语言..但为什么呢?

时间:2018-03-02 07:56:09

标签: ruby-on-rails ruby

我有我的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中,为什么授权方法在销毁审核之前不会中断和重定向用户?它实际上重定向,但删除审查后。但我认为红宝石是同步的..

3 个答案:

答案 0 :(得分:5)

正如其他人所说,你的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 :(得分:3)

在案例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实际上只为响应对象添加了适当的标头,它不会停止执行删除请求。

答案 2 :(得分:0)

在案例1中,您需要在执行重定向到停止执行时从方法返回

return redirect_to product_path(@review.product)

在案例2中,您必须在授权方法中进行一些更改。

场景1.对于特定用户角色,无法管理评论模型

unless can?(:manage, Review)
 redirect_to product_path(@review.product)
end

用模型名称

替换实例变量 方案2,某些具有特定角色的用户可以管理审核,但某些角色的其他用户无法管理审核。

在这种情况下,您需要在调用can函数

之前加载审阅对象
def authorize_user!
  find_review
  unless can?( :manage, @review)
    redirect_to product_path(@review.product)
  end
end

我认为我的回答会对你有帮助。