RailsでToDoサービスを作ろう(第4回)〜Punditで認可の権限管理する〜

2020年5月17日

にゅ〜ぶる
にゅ〜ぶる

こんにちは、にゅ〜ぶるです。

こんにちは〜、ぶるこだよ〜💕

ぶるこ
ぶるこ
にゅ〜ぶる
にゅ〜ぶる

さて、第4回目ですね!前回は、こちら
今日は、「Punditで認可の権限管理する」について、進めていきたいと思います!

にゅ〜ぶる
にゅ〜ぶる

Punditとは、認可の仕組みを提供してくれるライブラリ(Gem)です。
https://github.com/varvet/pundit

認可、つまり、ユーザが機能を使えるかどうかを判定する処理を行います。

にゅ〜ぶる
にゅ〜ぶる

では早速、使ってみましょう。
まずは、Gemfileに以下を追加します。

にゅ〜ぶる
にゅ〜ぶる

そして、Gemfileを修正したら「bundle install」ですね。

にゅ〜ぶる
にゅ〜ぶる

これでPunditが使えるようになりました。
次は、設定ファイルを作っていきます。
まずは、generatorが用意されているので、それを使います。

にゅ〜ぶる
にゅ〜ぶる

そうすると、app/policies/配下にapplication_policy.rbというファイルが作成されます。

にゅ〜ぶる
にゅ〜ぶる

initializerで定義されるuserはデフォルトでcurrent_userが引数に割り当てられるようになっているので、deviseを使ってログイン機能を作った際はそのまま利用できます。
recordの方には対応するモデルを割り当てていきます。※後述

にゅ〜ぶる
にゅ〜ぶる

では、この設定を有効にするために、有効にしたいControllerに次の1行を追加してください。各Controllerに追加しても良いですが、ApplicationControllerに追加する事で、継承されている全てのControllerで有効にする事ができますので、こちらを使いましょう。

にゅ〜ぶる
にゅ〜ぶる

次に、このファイルを継承して、各Controllerごとにファイルを作成していくことになります。

にゅ〜ぶる
にゅ〜ぶる

今回は、app/policies/配下にtask_policy.rbというファイルが作成しましょう。

にゅ〜ぶる
にゅ〜ぶる

モデル名_policy.rbでファイルを作成
モデル名Policyでクラスを作成
def アクション名?で認可ルールを作成

と言う感じです。
AppicationPolicyを継承しているため、独自にしたいアクション名のメソッドのみ作成すれば良いですが、AppicationPolicyのアクションに対応したメソッドを見て貰うと分かる通り、全てがfalseになっているため、全てが使えない状態になりますので、追加していきましょう。※後からでも良いです。

にゅ〜ぶる
にゅ〜ぶる

そして次は、各ControllerのアクションでPunditを使うように設定していきます。
各アクションに以下の1行を追加してください。

にゅ〜ぶる
にゅ〜ぶる

モデルのインスタンスを利用して判断する場合は、
 authorize モデルのインスタンス
 ※このインスタンスがrecordに設定されます。
使わない場合は、
 authorize モデル
と書き方が少し違います。

にゅ〜ぶる
にゅ〜ぶる

では、設定したので、実際にブラウザでアクセスしてみましょう。
「rails s」で起動させたのち、「http://localhost:3000/tasks」にアクセスしてみてください。

エラーが出るよおおお😭

ぶるこ
ぶるこ
にゅ〜ぶる
にゅ〜ぶる

そうですね。
前述した通り、Deviseなどを使っている場合は、current_userが存在しますが、今回は省略させて貰っているので、作る必要がありますね。

にゅ〜ぶる
にゅ〜ぶる

固定で申し訳ありませんが、作っておきましょう…

にゅ〜ぶる
にゅ〜ぶる

ではもう一度アクセスしてみてください。

まだエラー!!💢

ぶるこ
ぶるこ
pundit_error
にゅ〜ぶる
にゅ〜ぶる

落ち着いて、ちゃんとみてね笑

あ!
これが認可されなかったエラーなのか!
えへへ💕

ぶるこ
ぶるこ
にゅ〜ぶる
にゅ〜ぶる

そうなんだ。エラー画面を作る必要があるけど、まずは通常のエラー画面が出ればOKです。

にゅ〜ぶる
にゅ〜ぶる

では、各アクションの認可の仕組みを追加してみてください。
一覧画面や新規画面については、誰でもOKなので、常にtrueを返すようにしましょう。
参照や更新、削除については、そのTaskを作成したユーザが自分の場合のにOK(true)とする必要がありますね。

にゅ〜ぶる
にゅ〜ぶる

答えは、こんな感じ。

にゅ〜ぶる
にゅ〜ぶる

でも、これだけじゃダメですよ。
各アクションのメソッドで、Punditのauthorizeも必要ですね。

にゅ〜ぶる
にゅ〜ぶる

全てが完了したら、id=1のUserのTaskと、id=2のTaskを作るなどして、処理が正しく動いているか確認してみて下さい。

できたぁ💕

ぶるこ
ぶるこ
にゅ〜ぶる
にゅ〜ぶる

エラー画面については、rescue_fromを使ってごにょごにょしたり、固定のエラーページに飛ばしたり、強制でルートURLに遷移させたり、使い方は色々ありますので、自分にあった方法を見つけてみて下さい。

にゅ〜ぶる
にゅ〜ぶる

今回はここまでだよ。お疲れ様でした!
次回は、「一覧画面にRansack、kaminari」お楽しみにっ!!

最後まで読んでくれてありがとうございました!

現在、Railsのチュートリアル的な感じで、
「Todoサービスを作る!」をテーマにお送りしております。
アジェンダは、こちら

質問等ありましたら、コメントなりTwitterなりで頂ければ対応させて頂きますので、遠慮なく利用くださいね。