RailsのPundit設計ベストプラクティス完全解説!初心者でもわかる単純ルール化と責務分離のコツ
生徒
「Railsでログインした人によって、できることを変える方法ってあるんですか?」
先生
「あります。Railsでは認可という仕組みを使って、操作していいかどうかを判断します。その中でもPunditはとても人気があります。」
生徒
「Punditって難しそうな名前ですが、初心者でも使えるんですか?」
先生
「考え方をシンプルにすれば大丈夫です。今日は設計のコツを、身近な例で説明します。」
1. Railsにおける認可とは何か
Railsの認可とは、「その人がその操作をしてよいかどうか」を判断する仕組みです。例えば、掲示板アプリで「投稿を削除できるのは自分の投稿だけ」といったルールがあります。この判断をコードで書くのが認可です。
似た言葉に認証がありますが、これは「誰かを確認すること」です。ログインできたかどうかが認証で、ログイン後に何ができるかを決めるのが認可です。
2. Punditとは何かを超シンプルに理解する
PunditはRailsでよく使われる認可ライブラリです。特徴は「モデルごとにルールを書く」点です。Punditではポリシーというクラスを作り、その中に「この人はこの操作をしていいか」を書きます。
ポリシーは学校の校則のようなものです。生徒ごとに先生が毎回判断するのではなく、決まったルールを見て判断するイメージです。
3. ポリシー設計の基本構造
Punditでは、モデル名に対応したポリシークラスを作ります。例えばArticleモデルならArticlePolicyです。ポリシーには、show?やupdate?のようなメソッドを書きます。
class ArticlePolicy
attr_reader :user, :article
def initialize(user, article)
@user = user
@article = article
end
def update?
user == article.user
end
end
このコードは「ログインしている人と記事の持ち主が同じなら編集できる」という、とても単純なルールです。
4. 単純ルール化がなぜ重要なのか
Pundit設計で一番大切なのは、ルールを単純にすることです。「管理者ならOK、本人ならOK、それ以外はNG」など、短い文章で説明できる形が理想です。
条件を詰め込みすぎると、あとから読んだ自分でも意味がわからなくなります。認可は安全に直結するため、誰が見ても理解できるルールが重要です。
def destroy?
user.admin?
end
このように一行で意味が伝わる形が、良いPundit設計です。
5. 責務分離とは何かを身近な例で理解する
責務分離とは、「それぞれの役割を混ぜない」という考え方です。包丁で野菜を切り、フライパンで焼くように、役割ごとに道具を分けます。
Railsでは、コントローラは「流れの制御」、モデルは「データ管理」、Punditは「認可判断」と役割を分けます。コントローラに認可の細かい条件を書くのは避けます。
def update
@article = Article.find(params[:id])
authorize @article
@article.update(article_params)
end
コントローラでは「authorizeする」だけで、判断の中身はポリシーに任せています。
6. ポリシーに書くべきこと・書かないこと
ポリシーには「許可するかどうか」だけを書きます。データを保存したり、画面表示を変えたりする処理は書きません。
例えば「公開済みなら誰でも見られる」というルールはポリシー向きです。一方で「タイトルを変更する」といった処理はモデルやコントローラの役割です。
def show?
article.published? || user.admin?
end
7. 初心者がつまずきやすい設計ミス
よくある失敗は、ポリシーにif文を大量に書くことです。「もしAで、かつBで、さらにCなら…」と続くと理解が難しくなります。
そういう場合は、メソッドを分けたり、モデルに「状態」を表すメソッドを作って、ポリシーから呼び出すと読みやすくなります。
8. CanCanCanとの違いを軽く知っておく
Railsの認可にはCanCanCanもあります。CanCanCanは「一か所にルールを書く」方式で、Punditは「モデルごとに書く」方式です。
PunditはRailsの構造と相性がよく、責務分離を意識しやすい点が特徴です。初心者でもルールを追いやすい設計になります。