大ちゃんの駆け出し技術ブログ

RUNTEQ受講生のかわいいといわれるアウトプットブログ

Pundit

はじめに

こんにちは!大ちゃんの駆け出し技術ブログです。

最近は朝投稿が多いのでわりと朝活成功できています。

今日はRUNTEQの応用編で学習したgemの「Pundit」について発信しようと思います!

認可とは

Punditは"認可"の設定を効率よく行うためのgemです。

ん?認可とは何ぞや?

あまり聴き慣れない言葉ですよね。

認可というのは とある特定の条件に対して、リソースアクセスの権限を与えること

引用: https://dev.classmethod.jp/articles/authentication-and-authorization/

認可されることを具体例として管理者ページへのアクセスを使って説明すると

とある条件が「ユーザーが管理者ユーザーか」とであるとき、管理者ユーザーであれば管理者ページ(リソース)にアクセスする権限が与えられること」となります。

逆に一般ユーザーは管理者ページへのアクセスができないです。これが認可されないということになります。

gyazo.com

Punditの導入

Gemfileに追記してbundle install

# Gemfile
gem "pundit"
$ bundle
・
・
Fetching pundit 2.1.0
Installing pundit 2.1.0

アプリケーションコントローラに Punditincludeします。

class ApplicationController < ActionController::Base
  include Pundit
end

次に下記コマンドを実行します。

$ rails g pundit:install
Running via Spring preloader in process 47291
      create  app/policies/application_policy.rb

すると行数の多いファイルが作成されました。

# app/policies/application_policy.rb
class ApplicationPolicy
  attr_reader :user, :record

  def initialize(user, record)
    @user = user
    @record = record
  end

  def index?
    false
  end

  def show?
    false
  end

  def create?
    false
  end

  def new?
    create?
  end

  def update?
    false
  end

  def edit?
    update?
  end

  def destroy?
    false
  end

  class Scope
    attr_reader :user, :scope

    def initialize(user, scope)
      @user = user
      @scope = scope
    end

    def resolve
      scope.all
    end
  end
end

app/policies配下にファイルが置かれたように、Punditのファイルは全てこのディレクトリ配下に格納されます。applicationとあるように、こちらのファイルにはPunditのファイル全てに共通する内容を書きます。application_controller.rbなどと同じですね。

しかし、今回はよりPunditを理解するために固有の認可システムを作成します。例えば、このアプリケーションにBoard(掲示板)というモデルがあるとします。

このBoardを操作するにあたり、board_controller.rbupdateアクションに管理者ユーザーのみが行えるようにするとします。実装するためにapp/policies配下にboard_policy.rbを作成します。

# app/policies/board_policy.rb
class BoardPolicy
  attr_reader :user, :board

  def initialize(user, post)
    @user = user
    @post = post
  end

  def update?
    user.admin?
  end
end

次にboard_controller.rbupdateアクションにauthorizeメソッドをインスタンス変数を引数に使用します。

# app/controllers/boards_controller.rb
def update
  authorize @board
  if @board.update(board_params)
    redirect_to @board, success: t('defaults.message.updated', item: Board.model_name.human)
  else
    flash.now['danger'] = t('defaults.message.not_updated', item: Board.model_name.human)
    render :edit
  end
end

ここで何が行われるのかというと、updateアクションが実行時(掲示板を更新した時)、@boardからauthorizeメソッドはboard_policy.rbがあることを推測します。そして、現在実行されているアクション名に?が追加されたメソッドを探します。今回でいうと、board_policy.rbupdate?メソッドです。

def update?
  user.admin?
end

そしてuser.admin?tureを返さなければ、例外が発生します。これで管理者ユーザーのみがupdateアクションを実行することができ、一般ユーザーはupdateアクションを実行できなくなりました。これが認可を定義するPunditの力です!

終わりに

今回は簡単にざっくりとPunditを紹介しました!

1からアプリを実装しようとすると、ログイン機能を実装したりしなければならないので、今回は既存のアプリで試しました。みなさんもお手元の簡単なアプリで是非Punditを実装してみてください!

以上、大ちゃんの駆け出し技術ブログでした!