Help us understand the problem. What is going on with this article?

Rails4 + Devise + Authority + Rolifyで管理者権限付きの管理画面作成

More than 5 years have passed since last update.

掲題の件、最初はcancanを使おうと思ってたのですが開発がとまっているようでしたので、
Rails4 + Devise + Authority + Rolifyで管理者権限付きの管理画面を作成しました。
開発も活発で、使いやすかったため、今後また別の案件で使いたいと思ったのでメモに残したいと思います。

簡単な流れ

こちらのサイトを参考にしました

Gemfile
gem 'devise'
gem 'authority'
gem 'rolify'
  1. Deviseのインストールおよび設定(省略)
    rails generate devise:install
    rails generate devise User

  2. Authorityのインストール
    rails generate authority:install
    Authorityは、実際に各controllerのactionごとに、そのactionを実行できる条件を記述したりすることができます。
    またUserが指定した権限をもっているかどうかをチェックしたりできます。
    /app/authorizers/application_authorizer.rb
    /config/initializers/authority.rb
    が作成されます。

  3. Rolifyのインストール
    rails generate rolify:role
    Rolifyは、Userにroleを与えたり、指定したroleをもっているUserを探したりできます。
    たぶん4のスクリーンショットをみれば何となくどんな役割かは分かるかと思います。
    /config/initializers/rolify.rb
    が作成されます。

  4. Migration
    rake db:migrate
    スクリーンショット 2014-04-06 17.14.44.png

この2つのテーブル+deviseで作成されるUserテーブルが作成されます。

Authority + Rolifyの設定

基本的にはデフォルトの状態で良いかと思います。

/config/initializers/authority.rb
Authority.configure do |config|
  config.controller_action_map = {
    :index   => 'read',
    :show    => 'read',
    :new     => 'create',
    :create  => 'create',
    :edit    => 'update',
    :update  => 'update',
    :destroy => 'delete'
  }
  # 各actionがread create update deleteのどれに当てはまるか記載する。

  config.abilities =  {
    :create => 'creatable',
    :read   => 'readable',
    :update => 'updatable',
    :delete => 'deletable'
  }

  # deviseでcontrollerの継承を行っている場合に必要になることがある。
  # 例えば、deviseのデフォルトの'current_user'を、'current_admins_user'などとしている場合に、
  # 'current_admins_user'でAuthorityを利用できるようになる。
  config.user_method = :user_for_this_request
end
/app/authorizers/application_authorizer.rb
# Other authorizers should subclass this one
class ApplicationAuthorizer < Authority::Authorizer

  # 各controllerごとに権限管理をしたい場合は、application_authorizer.rbを継承します。
  # 以下は、権限を設定していないactionのデフォルトの設定になります。
  def self.default(adjective, user)
    true
  end

end

以下は、ApplicationAuthorizerを継承したUserAuthorizerになります。
以下の例の場合は、
update(edit update) create(create new) read(index show) はadminまたはeditorにアクセス権がある
delete(destroy)はadminにのみアクセス権がある
となります。
手動でファイル作成。

/app/authorizers/user_authorizer.rb
class UserAuthorizer < ApplicationAuthorizer

  def self.updatable_by?(user)
    user.has_role?(:admin) || user.has_role?(:editor)
  end

  def self.creatable_by?(user)
    user.has_role?(:admin) || user.has_role?(:editor)
  end

  def self.readable_by?(user)
    user.has_role?(:admin) || user.has_role?(:editor)
  end

  def self.deletable_by?(user)
    user.has_role?(:admin)
  end

end

モデルに記述を追加します。

/app/models/user.rb
class User < ActiveRecord::Base

  # creatable_by?(user)などのメソッドが利用できるようになる。
  include Authority::Abilities

  # can_create?(resource)などのメソッドが利用できるようになる。
  include Authority::UserAbilities

  # 権限の設定は、/app/authorizers/user_authorizer.rbを参照する
  self.authorizer_name = 'UserAuthorizer'

  # roleを適用したいmodelの中に記載
  resourcify

  #以下のコールバックが利用できるようになる。
  rolify
  # Userを追加した際にデフォルトでeditor roleを割り当てるための設定。
  # 他にも、削除する前、削除した後、作成する前、作成した後といったコールバックが用意されている。
  after_create :assign_default_role

  def assign_default_role
    self.add_role(:editor)
  end

  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable#, :confirmable
end

controllerに記述を追加します。
僕は管理画面作成のためにadminsコントローラーを継承させています。

/app/controllers/admins/users_controller.rb
class Admins::UsersController < AdminsController
  alias :user_for_this_request :current_admins_user
  # show action以外は、user_authorizer.rbを使用する
  authorize_actions_for User, except: :show

  def index
    @users = User.all
  end

  def show

  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_user
      @user = User.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def user_params
      params
        .require(:user)
        .permit(:email, :password, :password_confirmation)
    end

end

deviseのcontrollerを継承させて、拡張している場合はこちらにも記載を。

/app/controllers/admins/users/registrations_controller.rb
class Admins::Users::RegistrationsController < Devise::RegistrationsController
  alias :user_for_this_request :current_admins_user
  authorize_actions_for User
end

その他viewやエラーハンドリングなど

application_controllerでエラーを捕そくして、「アクセス権がありません」などといったページを表示させるといいかと思います。

/app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  rescue_from Authority::SecurityViolation, with: :authority_forbidden
  def authority_forbidden(error)
    Authority.logger.warn(error.message)
    render file: "#{Rails.root}/public/403.html", status: 403, layout: 'error'
  end
end

viewでも、例えば削除権限のないUserに対しては、削除ボタンなんかは非表示にしておくと親切ですね。

/app/views/admins/users/index.html.slim
- if current_admins_user.has_role? :admin
  #管理者User用の処理
- else
  #それ以外のUser用の処理

最終的にこんな権限表を用意して見やすくしてみました。
スクリーンショット 2014-04-06 18.33.11.png

ファイル内にコメントアウトで説明があるので分かるかと思いますが、
ActiveRecordを利用しない場合や、user.is_admin?のようなショートカットを設定したい場合などには、以下のようにするそうです。(動作未確認)

/config/initializers/rolify.rb
Rolify.configure do |config|
  config.use_mongoid
  config.use_dynamic_shortcuts
end

参照

AuthorityにはAuthorizerメソッドの優先順位があるとのことで、これについては既に詳しく記事にしてくださっている方がおりました。感謝。
authority gem の Authozier メソッドの優先順位について
github Rolify
github Authority

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away