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

问题描述 投票:0回答:3

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

ruby-on-rails ruby
3个回答
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

Update

你可以整合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

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


0
投票

在情况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

我想我的回答会对你有所帮助。

© www.soinside.com 2019 - 2024. All rights reserved.