偏执狂和CanCanCan之间的Rails 5兼容性受到损害吗? [英] Rails 5 compatibility between Paranoia and CanCanCan, compromised?

查看:92
本文介绍了偏执狂和CanCanCan之间的Rails 5兼容性受到损害吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到了与该线程中所述完全相同的问题:

I'm having the exact same issue as described on this thread:

仅5条轨道_已删除cancancan#356

我可以访问已删除的记录,如下所示:

I can access a deleted record, like this:

    @area = Area.only_deleted.find(params[:id])

但是如果我将load_and_authorize_resource添加到控制器中,它将尝试运行如下查询:

but if I add load_and_authorize_resource to my controller, it'll attempt to run the query like this:

    @area = Area.find(params[:id])

这将导致错误,因为它将无法在不包含delete_at不为null的集合(未删除的记录,这是Paranoia gem的目的)上找到具有该ID的记录.

which will result in error since it won't find a record with that id on a collection where deleted_at isn't null (not deleted records, the purpose of the Paranoia gem).

如果我禁用控制器或该动作的load_and_authorize_resource,它可以解决错误,但这不是解决方案,因为这意味着失去授权控制.

If I disable load_and_authorize_resource for the controller or for that very action, it solves the error but it's not a solution since that means losing authorization control.

是否已解决此问题,或者是否有可以与我切换到的Rails 5上的Paranoia配合使用的授权gem?

Is there a fix for this, or is there an authorization gem which plays nice with Paranoia on Rails 5 which I could switch over to?

谢谢.

推荐答案

因此,根据有关load_and_authorize_resource 的文档,如果尚未设置实例变量,该方法将尝试加载实例变量;如果存在已设置的实例变量,则该方法将不会加载该实例变量.为什么应用程序被破坏了:

So, according to documentation on load_and_authorize_resource, the method will attempt to load an instance variable in case one hasn't been set yet, and won't do so if there's a set instance variable, which is precisely why the application was breaking:

class AreasController < ApplicationController

  load_and_authorize_resource

  before_action :set_area, only: [:show, :edit, :update, :destroy]

  ...     

  def set_area
    if session[:show_obsolete_records] == true
      @area = Area.only_deleted.find(params[:id])
    else
      @area = Area.find(params[:id])
    end
  end
end

load_and_authorize_resource首先在列表上运行,并且由于在调用之前没有设置实例变量,因此它会自行执行@area = Area.find(params[:id]),这显然会导致错误,因为 Paranoia 会覆盖查找程序方法,其中包含检查deleted_at是否为NULL的条件.

load_and_authorize_resource runs first on the list, and since there were no instance variables set before its call, it does @area = Area.find(params[:id]) on its own account, which obviously leads to error, since Paranoia overwrittes finder methods to include a condition to check whether the deleted_at is NULL.

例如,当使用常规(不使用妄想症)Area.find(17)时,您会在控制台上收到如下查询:

For example, when using the regular (without Paranoia) Area.find(17), you get a query like this on your console:

Area Load (0.2ms)  SELECT  "areas".* FROM "areas" WHERE "areas"."id" = ? LIMIT ?  [["id", 17], ["LIMIT", 1]]

使用 Paranoia 时,您会收到以下查询:

When using Paranoia, you'd get this query:

Area Load (0.2ms)  SELECT  "areas".* FROM "areas" WHERE ("areas"."deleted_at" IS NULL) AND "areas"."id" = ? LIMIT ?  [["id", 17], ["LIMIT", 1]]

这样,由于已设置了deleted_at时间戳记(deleted_at现在为NOT NULL),因此在常见查询中不会找到已删除的记录.

This way, records that have been deleted won't be found on common queries since they'll have the deleted_at timestamp set (deleted_at is now NOT NULL).

要访问已删除的记录,您必须使用with_deletedonly_deleted,例如

To access deleted records, you must use either with_deleted or only_deleted, like

@area = Area.only_deleted.find(params[:id])

否则它将找不到删除的记录,因此为什么我会得到错误

or else it won't find the deleted record, hence why I was getting the error

ActiveRecord::RecordNotFound - Couldn't find Area with 'id'=16 [WHERE "areas"."deleted_at" IS NULL]:

方法load_and_authorize_resource加载了@area = Area.find(params[:id])并跳过了set_area,因此您可以删除该方法,即使代码不存在,该方法仍会设置区域.

The method load_and_authorize_resource loaded @area = Area.find(params[:id]) and skipped set_area, so you could delete the method and it would still set the area even if the code is not there.

解决方案是将load_and_authorize_resource方法简单地移到回调列表下方:

The solution is to simply move the load_and_authorize_resource method below the callbacks list:

class AreasController < ApplicationController

  before_action :set_area, only: [:show, :edit, :update, :destroy]

  load_and_authorize_resource

  ...     

  def set_area
    if session[:show_obsolete_records] == true
      @area = Area.only_deleted.find(params[:id])
    else
      @area = Area.find(params[:id])
    end
  end
end

更新

您可以将方法调用load_and_authorize_resource留在堆栈的顶部,但是将其更改为authorize_resource,这样它就不会尝试调用@area = Area.find(params[:id]),根据

You can leave the method call load_and_authorize_resource at the top at the stack, but change it to authorize_resource so it doesn't attempt to call @area = Area.find(params[:id]), according to this thread.

class AreasController < ApplicationController

  authorize_resource

  before_action :set_area, only: [:show, :edit, :update, :destroy]

  ...     

  def set_area
    if session[:show_obsolete_records] == true
      @area = Area.only_deleted.find(params[:id])
    else
      @area = Area.find(params[:id])
    end
  end
end

这篇关于偏执狂和CanCanCan之间的Rails 5兼容性受到损害吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆