68
69

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

CanCanを使って複数のモデルに対して異なった権限(Ability)を設定する

Posted at

CanCan を使うとユーザモデルが各リソースに対してアクセスする際の CRUD 権限を付与できるが、
ユーザモデルが複数になった場合、それぞれに異なった権限を設定したくなるかと思います。

User モデルと Admin モデルがそれぞれ以下のような役割を持つ

■User
・一般ユーザには各リソースに対して参照権限と修正権限を付与
・特別なユーザには各リソースに対して作成権限、参照権限、修正権限、削除権限の全てを付与

■Admin
・カスタマーサポートには各リソースに対して参照権限を付与
・サービス管理者には各リソースに対して参照権限、修正権限、削除権限を付与

このような場合は、Ability クラスを複数に分けて権限を設定すると、幸せになれます。

モデルを作成して役割を与える

今回はユーザモデルの作成に devise を使用し、役割の判別は Rails 4.1 より追加された enum を使いますが、もちろん他の方法でも問題ありません。

bash
$ rails generate devise User
$ rails generate devise Admin
$ rails generate migration AddRoleToUsers role:integer
$ rails generate migration AddRoleToAdmins role:integer
$ rake db:migrate
user.rb
class User < ActiveRecord::Base

  enum role: {general: 1, special: 2}

end
admin.rb
class User < ActiveRecord::Base

  enum role: {support: 1, manager: 2}

end

権限を設定する

権限設定には CanCan を引き継いだ CanCanCan を使用し、設定は複数の Ability クラスを作成して行います。

bash
$ rails generate cancan:ability
      create  app/models/ability.rb
$ cp -ip app/models/ability.rb app/models/user_ability.rb
$ cp -ip app/models/ability.rb app/models/admin_ability.rb
user_ability.rb
class UserAbility
  include CanCan::Ability

  def initialize(user)
    if user.general?
      can :read, :all
      can :update, :all
    elsif user.special?
      can :manage, :all
    end
  end

end
admin_ability.rb
class AdminAbility
  include CanCan::Ability

  def initialize(admin)
    if admin.support?
      can :read, :all
    elsif admin.manager?
      can :read, :all
      can :update, :all
      can :destroy, :all
    end
  end

end

コントローラで適用する権限設定を振り分ける

ここが最も重要になりますが、CanCan::ControllerAdditionscurrent_ability を上書きします。

application_controller.rb
class ApplicationController < ActionController::Base  

  def current_ability
    if user_signed_in?
      @current_ability ||= ::UserAbility.new(current_user)
    elsif admin_signed_in?
      @current_ability ||= ::AdminAbility.new(current_admin)
    else
      @current_ability ||= ::Ability.new(nil)
    end
  end

end

この設定を入れることで、User でログインしている場合は UserAbility に設定した権限が適用され、
Admin でログインしている場合は AdminAbility に設定した権限が適用されます。
なお、未ログイン状態のユーザに対しては、Ability に設定した権限が適用されます。

68
69
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
68
69

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?