Rails 5 Paranoia 和 CanCanCan 之间的兼容性受到损害?
Rails 5 compatibility between Paranoia and CanCanCan, compromised?
我遇到的问题与此线程中描述的完全相同:
Rails 5 only_deleted with cancancan #356
我可以像这样访问已删除的记录:
@area = Area.only_deleted.find(params[:id])
但如果我将 load_and_authorize_resource
添加到我的控制器,它将尝试 运行 查询,如下所示:
@area = Area.find(params[:id])
这将导致错误,因为它不会在 deleted_at 不为空的集合中找到具有该 ID 的记录(未删除的记录,Paranoia gem 的目的) .
如果我为控制器或那个动作禁用 load_and_authorize_resource
,它可以解决错误,但这不是解决方案,因为这意味着失去授权控制。
是否有解决此问题的方法,或者是否有授权 gem 可以在 Rails 5 上与 Paranoia 配合使用,我可以切换到?
谢谢。
因此,根据 documentation on load_and_authorize_resource,如果尚未设置实例变量,该方法将尝试加载一个实例变量,如果有一个已设置的实例变量,则不会这样做,这恰恰是应用程序崩溃的原因:
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 覆盖 finder 方法以包含检查 deleted_at
是否为 NULL
.
的条件
例如,当使用常规(没有 Paranoia)Area.find(17)
时,您会在控制台上收到如下查询:
Area Load (0.2ms) SELECT "areas".* FROM "areas" WHERE "areas"."id" = ? LIMIT ? [["id", 17], ["LIMIT", 1]]
当使用 Paranoia 时,你会得到这个查询:
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
)。
要访问已删除的记录,您必须使用with_deleted
或only_deleted
,例如
@area = Area.only_deleted.find(params[:id])
否则它不会找到已删除的记录,这就是我收到错误的原因
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
,因此您可以删除该方法,即使代码不存在,它仍会设置区域。
解决方法是简单地将 load_and_authorize_resource
方法移动到回调列表下方:
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
更新
根据 .
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
我遇到的问题与此线程中描述的完全相同:
Rails 5 only_deleted with cancancan #356
我可以像这样访问已删除的记录:
@area = Area.only_deleted.find(params[:id])
但如果我将 load_and_authorize_resource
添加到我的控制器,它将尝试 运行 查询,如下所示:
@area = Area.find(params[:id])
这将导致错误,因为它不会在 deleted_at 不为空的集合中找到具有该 ID 的记录(未删除的记录,Paranoia gem 的目的) .
如果我为控制器或那个动作禁用 load_and_authorize_resource
,它可以解决错误,但这不是解决方案,因为这意味着失去授权控制。
是否有解决此问题的方法,或者是否有授权 gem 可以在 Rails 5 上与 Paranoia 配合使用,我可以切换到?
谢谢。
因此,根据 documentation on load_and_authorize_resource,如果尚未设置实例变量,该方法将尝试加载一个实例变量,如果有一个已设置的实例变量,则不会这样做,这恰恰是应用程序崩溃的原因:
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 覆盖 finder 方法以包含检查 deleted_at
是否为 NULL
.
例如,当使用常规(没有 Paranoia)Area.find(17)
时,您会在控制台上收到如下查询:
Area Load (0.2ms) SELECT "areas".* FROM "areas" WHERE "areas"."id" = ? LIMIT ? [["id", 17], ["LIMIT", 1]]
当使用 Paranoia 时,你会得到这个查询:
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
)。
要访问已删除的记录,您必须使用with_deleted
或only_deleted
,例如
@area = Area.only_deleted.find(params[:id])
否则它不会找到已删除的记录,这就是我收到错误的原因
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
,因此您可以删除该方法,即使代码不存在,它仍会设置区域。
解决方法是简单地将 load_and_authorize_resource
方法移动到回调列表下方:
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
更新
根据
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