1
0

More than 3 years have passed since last update.

権限のないユーザーが削除することを制限する方法

Posted at

目的

以下のコード before_action :redirect, only: [:edit, :update]にdestroyアクションを追加します。削除機能は特定のユーザーのみ実行できる必要があるため、privateアクション内で定義する「特定のユーザーでなければindexのページまでredirectする」仕様にdestroyアクションを追加します。

手順

以下、現在のitems_controllerを修正します。

items_controller.rb
class ItemsController < ApplicationController
  before_action :authenticate_user!, except: [:index, :show]
  before_action :set_item, only: [:show, :edit, :update]
  before_action :redirect, only: [:edit, :update]
  def index
    @items = Item.order('created_at DESC')
  end

  def new
    @item = Item.new
  end

  def create
    @item = Item.new(item_params)
    if @item.save
      redirect_to root_path
    else
      render :new
    end
  end

  def show
  end

  def edit
  end

  def update
    if @item.update(item_params)
      redirect_to root_path
    else
      render :edit
    end
  end

  def destroy
    item = Item.find(params[:id])
    if item.destroy
      redirect_to root_path
    end
  end

  private

  def item_params
    params.require(:item)
          .permit(:product_name, :category_id, :price, :product_status_id, :burden_id, :area_id, :days_id, :description, :image)
          .merge(user_id: current_user.id)
  end

  def set_item
    @item = Item.find(params[:id])
  end

  def redirect
    unless current_user.id == @item.user.id
      redirect_to action: :index 
    end
  end
end

まずは

  before_action :redirect, only: [:edit, :update]

 before_action :redirect, only: [:edit, :update, :destroy]

とします。
次に、destroyメソッドを修正します。

  def destroy
    item = Item.find(params[:id])
    if item.destroy
      redirect_to root_path
    end
  end

  def destroy
    # @item = Item.find(params[:id])
    if @item.destroy
      redirect_to root_path
    end
  end

privateメソッド内のredirectメソッドを見ると、変数が@item
となっています。そのため、destoryメソッドの変数も@itemに変更します。(以下で説明しますが@item = Item.find(params[:id])はコメントアウトしています。)
しかし、このまま実行すると、@itemがnill_class(空)であるというエラーが生じます。その理由は、
destroyアクションで変数@itemが生成されていないためです。
before_action:redirect内にdestroyを入れたことで、先にprivateメソッドが実行されます。すると、redirectメソッド内の
unless current_user.id == @item.user.id
がdestoryアクション内で
@item = Item.find(params[:id])
と定義する前に実行されてしまいます。
destroyアクションで変数@itemが生成されていないため、nill_classというエラーが生じました。

そこで、berore_action内に
@item = Item.find(params[:id])
を定義するようにします。

before_action :set_item, only: [:show, :edit, :update]

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

set_itemメソッド内にdestroyを組み込むことで、privateメソッドが実行される前に変数@itemを生成します。
destroyアクション内では
@item = Item.find(params[:id])
は必要ないので、消去します。(今回は分かりやすいように上記の通りコメントアウトしております)

以上で、destroyアクションをredirectアクションに組み込むことができました。

発展

※ここからは発展です。実装とは関係がありません。
そもそも、destroyアクションはviewページを持たないため、URLで直接アクセスする事ができません。あくまで、別のviewページで削除ボタンを押すとdestroyアクションが実行されるのみです。

    unless current_user.id == @item.user.id
      redirect_to action: :index 
    end
  end

とredirectをかける必要はないのでしょうか。

結論

あります。
viewページ上では確かに削除を実行することはできません。しかし、検証ツールを用いることで、削除権限のないユーザーが削除ボタンを作ることができるそうです。そのため、検証ツール上で権限のないユーザーが削除を実行することは可能だそうです。(今回の実装ではviewページ上では権限のないユーザーには削除ボタンを表示させないようにしております。)

以上、処理の実行に対する権限に関しては非常に勉強になりました。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0