したがって、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
。
たとえば、通常の (パラノイアなし)を使用する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
is now ) 、一般的なクエリでは見つかりません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
アップデート
このスレッドによると、メソッド呼び出しload_and_authorize_resource
をスタックの一番上に残すことができますが、呼び出しをauthorize_resource
試行しないように変更します。@area = Area.find(params[:id])
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