👖

アクセス制限を設定しURL入力による遷移を阻止する

2023/10/01に公開

この記事で分かること

  • アクセス制限の設定方法
完成コード
app/product_controllers
class Public::ProductsController < ApplicationController
   before_action :authenticate_user!
+  before_action :ensure_current_user, {only: [:edit, :update, :show]}

  def new
     @user = User.find(params[:user_id])
     @product = Product.new
  end

  def index
    @user = User.find(params[:user_id])
    @release_products = @user.products.where(is_secret: true).page(params[:page])
    @secret_products = @user.products.where(is_secret: false)
    @products = @user.products
    @reviews = Review.all
  end

  def create
    @product = Product.new(product_params)
    @user = User.find(params[:user_id])
    @product.user_id = @user.id
    if @product.save
     flash[:notice] = "商品を登録しました"
     redirect_to user_products_path(@user)
    else
      flash[:alert] = "正しい内容を入力してください"
      render :new
    end
  end

  def show
    @user = User.find(params[:user_id])
    @product = Product.find(params[:id])
    @review = Review.new
    @reviews = @product.reviews.includes(:user)
    @all_rating = '総合評価'
  end

  def edit
     @user = User.find(params[:user_id])
     @product = Product.find(params[:id])
  end

  def update
    @user = User.find(params[:user_id])
    @product = Product.find(params[:id])

    if current_user == @user
      if params[:is_secret] == "公開中"
        flash[:notice] = "商品を公開しました"
        @product.is_secret = true
      elsif params[:is_secret] == "非公開"
        flash[:notice] = "商品を非公開にしました"
        @product.is_secret = false
      else
        flash[:notice] = "商品の設定を更新しました"
        @product.update!(product_params)
      end

      if @product.save!
        redirect_to user_product_path(@user)
      else
        render "edit"
        flash[:alert] = "更新に失敗しました"
      end
    else
      render "edit"
      flash[:alert] = "更新に失敗しました"
    end
  end

   private

   def product_params
     params.require(:product).permit(:name, :introduction, :price, :image, :active_status, :genre_id ,:user_id, :item_id, :is_secret,)
   end

+ def ensure_current_user
+    @user = User.find(params[:user_id])
+    @product = Product.find(params[:id])
+   if @product.is_secret == false && current_user.id != params[:user_id].to_i
+      flash[:alert]="閲覧権限がありません"
+      redirect_to user_products_path(@user)
+   end
+ end
end

前提条件

  • deviseが実装済み
  • アクセス制限したい部分の機能やページが実装済み
  • Routingでは、親 : 子 = User : Productの関係を持つ

現状の問題点

投稿ユーザーの画面

before_products/index

before_products/show

閲覧ユーザーの画面

issue_products_index1

issue_products_index2

issue_products_show

テーブル

table_products

  • 本記事ではProductsカラムの「is_secret」を使用します。
is_secret

データ型はbool型で、公開商品ならば(true),非公開ならば(false)を持ちます。
今回の目的は、非公開商品かつ投稿したユーザーでないならば、URL遷移できない設定にするため、if文で「is_secret == false」を使います。

実装手順

  • before_actionで制限を設ける
before_actionとは?

アクションを実行する前に特定の処理を実行するためのもの
ex) createアクションで商品登録するアクションを行うならば、createアクションを実行する前に before_actionでログインユーザーの情報を確認するアクションを実行できる

  • 基盤となるコード
before_action :メソッド名

実装方法

before_actionの内容を定義します。

app/product_controllers
 before_action :ensure_current_user, {only: [:edit, :update, :show]}

  def ensure_current_user
     @user = User.find(params[:user_id])
     @product = Product.find(params[:id])
    if @product.is_secret == false && current_user.id != params[:user_id].to_i
       flash[:alert]="閲覧権限がありません"
       redirect_to user_products_path(@user)
    end
  end
解説
  • {only: [:edit, :update, :show]}
    → edit,update,showアクションの時に実行する

  • @product.is_secret == false
    → 非公開商品に限定する

  • current_user.id != params[:user_id].to_i
    →「ログインユーザーIDがURLのユーザーIDと一致しなければ」という意味
    → params[:user_id]で取得できる値は「文字列」であるため、整数型に変換する(.to_i)

以上で完成です。(全体のコードは「完成コード」を参照)

complate

  • 閲覧ユーザーの画面でURL遷移を実行し権限を確認

感想

この問題はメンターさんからのフィードバックで気づくことができました。1人だと気づきにくい部分かもしれませんが大事な要素なので見落とさないように注意していきたいです。

この記事をかいた人

https://twitter.com/tya_dwc
23/6/1にDWCに入学し、主にRailsの学習に取り組みました。卒業が近づきこれから何で学習をするか悩んだときに、技術ブログをしようと考えました。初心者ですがよろしくお願いします。

Discussion