RoleRequirement プラグインについて
現在、rails のアカウント管理系プラグインのデファクトスタンダードといえば acts_as_authenticated である。
このプラグインに「ロール」の概念を追加するプラグインとして role_requirement(RoleRequirement) プラグインがある。
このプラグインは非常に直感的にコントローラ、アクションごとのロールの適用を可能とする。
下記の例ではシステム管理用のコントローラ SystemController が admin ロールを持ったユーザのみがアクセスできると記述していることになる。
class SystemController < ApplicationController require_role "admin" # ... end
ただし、ロールを満たせなかった場合の挙動が以下のように実装されておりいただけない。
- 401 Unauthorized レスポンスを返す
- なにも描画しない
以下、自分が行なった対応をまとめる。RoleRequirement プラグインのバージョンは 1.3.2 である。
実装を確認すると、lib/role_requirement_system.rb の RoleSecurityInstanceMethods#access_denied メソッドに問題があるようである。
def access_denied if logged_in? render :nothing => true, :status => 401 return false else super end end
L.113 の render メソッドにすべてが集約されている。これを、以下のように修正する。
- 401 Unauthorizedレスポンスを返さない
- 任意のコントローラ・アクションを描画する
- 権限のないアクセスはサイト内で一律同じURLへリダイレクトする
まずは lib/role_requirement_system.rb に対する patch から。
Index: C:/ruby/rails/trunk/lib/role_requirement_system.rb =================================================================== --- C:/ruby/rails/trunk/lib/role_requirement_system.rb (revision 24) +++ C:/ruby/rails/trunk/lib/role_requirement_system.rb (working copy) @@ -110,7 +110,7 @@ def access_denied if logged_in? - render :nothing => true, :status => 401 + self.url_for_access_denied ? redirect_to(self.url_for_access_denied) : redirect_to("/") return false else super
self はリクエストされたコントローラのインスタンスであり、url_for_access_denied は ApplicationController へ新たに定義したアクセサで以下のように定義している。
class ApplicationController < ActionController::Base attr_accessor :url_for_access_denied def initialize @url_for_access_denied = {:controller => :home} end end
@url_for_access_denied が設定されず nil であれば "/" へリダイレクトされるようにしてあるのでこれでも十分かもしれない。
RoleRequirement プラグイン自体はよくできているのでこの対応をいれればより使いやすくなるだろう。