IT技術にまつわる実験ノート

「長編を書くより、短編を数多く完成させてください。それが上達への近道です」 by 手塚治虫

自作Webアプリ「IT勉強会用 名刺ジェネレーター」を公開しました!ぜひご活用ください😀

https://it-benkyoukai-meishi.herokuapp.com/

pundit を使ってみる

はじめに

ここでは以下の記事を参考にして、pundit を使ってみることにする。

 

使ってみる

ざっくりとアプリを作成する。

  • rails new pundit_blog
  • cd pundit_blog

 

gem をインストールする。

  • echo "" >> Gemfile
  • echo "gem 'devise'" >> Gemfile
  • echo "gem 'pundit'" >> Gemfile
  • bundle

 

モデルを作成する。

  • bin/rails g devise:install
  • bin/rails g devise User
  • bin/rails g scaffold Article user:references title:string content:text
  • bin/rails db:migrate

 

pundit のジェネレーターを実行する。

  • bin/rails g pundit:install

 

これで app/policies/application_policy.rb が作成される。

f:id:matt-note:20190221232340p:plain

 

Article ポリシーを作成してみる

pundit のジェネレーターで article 用のポリシーを作成する。

  • bin/rails g pundit:policy article

 

これで ApplicationPolicy を継承した ArticlePolicy を作成される。

f:id:matt-note:20190407211139p:plain

コントローラの設定をする。application_controller.rb で Pundit モジュールをインクルードする。これでコントローラで pundit のメソッドを使用できるようになる。

f:id:matt-note:20190221233936p:plain

 

articles_controller.rb の index アクションで authorize メソッドを使ってみる。

f:id:matt-note:20190407201343p:plain

 

authorize メソッドの定義は以下のようになっている。引数には record を渡すようになっている。queryはアクション名から暗黙的に取得するような実装になっている。authorize メソッドによって current_user が record に対して query を実行できるかチェックするとのこと。(ここでは current_user が @articles に対して index アクションを実行できるかチェックする。)

f:id:matt-note:20190417172906p:plain

 

サーバーを起動して、ユーザー登録をして、localhost/articles にアクセスしてみる。ArticlesController#index に対して Pundit::NotAuthorizedError が発生した。

f:id:matt-note:20190407200651p:plain

 

ApplicationPolicy クラスの index? メソッドは、デフォルトで false を返すようになっている。そのため ApplicationPolicy クラスを継承した ArticlePolicy でも、この index? によって、アクセスできないようになっている。

f:id:matt-note:20190221234551p:plain

 

記事一覧を閲覧できるようにする。article_policy.rb を編集して、index? メソッドをオーバーライドする。これで current_user が Article#index アクションを実行をすることを許可する設定ができた。

f:id:matt-note:20190407211025p:plain

 

コントローラで authorize メソッドを明示的に書く場合は、第二引数に article_policy.rb でチェックするメソッドを追加する。これで current_user が @articles に対して閲覧できるのか(index?)をチェックするようになる。index? メソッドの戻り値は true に設定したので、記事を閲覧できるようになる。

f:id:matt-note:20190417173422p:plain

 

もう一度、localhost/articles にアクセスしてみる。

f:id:matt-note:20190407201229p:plain

-> current_user で Article#index アクションを実行できるようになった。

 

個別ページは記事の作成者だけが閲覧できるようにしてみる

article_policy.rb で show? メソッドをオーバーライドする。

f:id:matt-note:20190407223001p:plain

 

articles_controller.rb の show アクションで authorize メソッドを実行する。

f:id:matt-note:20190407223212p:plain

 

application.html.erb でログイン関係のリンクを作成しておく。

f:id:matt-note:20190407223330p:plain

 

ログインユーザーが記事を作成して、他のログインユーザーがその記事を読もうとすると、エラーにすることができる。

f:id:matt-note:20190407223433p:plain


ロール別の権限を定義してみる。

  • bin/rails g migration AddRoleToUser role:integer

 

マイグレーションファイルに制約を記述する。

f:id:matt-note:20190407232220p:plain

 

マイグレーションを実行する。

 

User モデルでロールを定義する。ついでに、新しく作成したレコードのロールは自動的に standard になるように設定する。

f:id:matt-note:20190407235429p:plain



rails c でコンソールを起動して admin ユーザーを作成する。

f:id:matt-note:20190407232704p:plain

f:id:matt-note:20190407232812p:plain

f:id:matt-note:20190407232848p:plain


削除ボタンを管理者にだけ表示させるようにしてみる

article_policy.rb で destroy? メソッドをオーバーライドする。user.admin? メソッドが true になる場合は、destroy アクションを実行できるようになる。

f:id:matt-note:20190408000254p:plain

 

コントローラの destroy アクションで authorize メソッドを実行する。ここでは記事を destroy する前に authorize メソッドで削除できるかチェックしておく。これで管理者にだけ表示された削除リンクを押すと、管理者にだけ記事の削除ができるようになる。

f:id:matt-note:20190408001008p:plain

 

index.html.erb で policy ヘルパーを呼び出す。ここでの destroy? メソッドは、ユーザーが管理者の時だけ true になるので、管理者にだけ削除リンクが表示されることになる。

f:id:matt-note:20190408001532p:plain

 

application_controller.rb で verify_authorized  メソッドを使ってみる。

f:id:matt-note:20190222000306p:plain

localhost/posts/new にアクセスすると、Pundit::AuthorizationNotPerformedError となった。

f:id:matt-note:20190222000418p:plain

index.html.erb で以下のようにしてみる。

f:id:matt-note:20190222001436p:plain

PostPolicy クラスの new? メソッドは false を返すので、リンクが非表示になる。

f:id:matt-note:20190222001513p:plain

app/policies/post_policy.rb で new? メソッドをオーバーライドしてみる。

f:id:matt-note:20190222001711p:plain

PostPolicy クラスの new? メソッドで true を返すので、リンクを表示できるようになった。

f:id:matt-note:20190222001746p:plain