1

このスレッドで説明されているのとまったく同じ問題が発生しています。

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 が null でないコレクションでその id を持つレコードが見つからないため、エラーが発生します (Paranoia gem の目的である削除されたレコードではありません)。

コントローラーまたはそのアクションを無効load_and_authorize_resourceにすると、エラーは解決しますが、承認制御が失われるため、解決策ではありません。

これを修正する方法はありますか、それとも Rails 5 の Paranoia でうまく動作する認証ジェムはありますか?

ありがとうございました。

4

1 に答える 1

0

したがって、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_atis now ) 、一般的なクエリでは見つかりませんNOT NULL

削除されたレコードにアクセスするには、またはのいずれかを使用する必要があります。with_deletedonly_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
于 2016-10-06T19:00:27.867 に答える