LoginSignup
0
0

More than 1 year has passed since last update.

【Rails】CanCanCanでリソースが特定の条件を満たすときのみ権限を付与する方法

Posted at

Railsにおいて権限設定を簡単に実装できる方法は、Cancancanを使うことが1つの手段として考えられます。
https://github.com/CanCanCommunity/cancancan
cancancanを使った権限設定では、特定の条件を満たすリソースについては特定のアクションを許可したい、という場合があります。
そんな時に取れる対応方法を紹介します。

想定ケース

ユーザーは、企業名(name)にhogeの文字列を含む企業についてはメールを送れる。

こんな権限設定がしたいとします。
準備として、companyモデルで「名前にhogeが入っている」ことを判定するインスタンスメソッドを定義します。

company.rb
class Company < ApplicationRecord
...(略)

  def include_hoge?
    name.include?('hoge')
  end
end

Abilityの書き方

この場合、ブロックを使って以下のように書くと、上記を満たす権限設定を書くことができます。

ability.rb
class Ability
  include Cancan::Ability

  def initialize(user)
    can :send_mail, Company, { include_hoge?: true }
  end
end

Companyの中から、include_hoge?がtrueを返す企業に対してのみ:send_mailの権限を付与できます。

ControllerやViewで使うのは基本の使い方と同じ

一応注意点として、この方法だと、authorize_resourceを使って自動的にaction名と一致した権限を見る、といったことができなくなるので、
before_actionやaction内でauthorize!メソッドを使いながら権限チェックをすることになると思います。

  • Controllerで使いたい時
foo_controller.rb
FoosController < < ApplicationController
  def xxx
    @company = Company.find(params[:id])
    authorize! :send_mail, @company
    ...(略)
  end
end
  • Viewで使いたい時
xxx.html.erb
<% if can? :send, @company %>
  ...(略) <%# 権限があるときに表示したい項目を書く %>
<% end %>

他の方法(あまり良くないと思われる)

別の方法として、Abilityクラスのinitializeの引数でcompanyを受け取る方法でも同じことが実現できるように見えます。

ability.rb
class Ability
  include Cancan::Ability

  def initialize(user, company: nil)
    can :send_mail, Company if company&.include_hoge?
  end
end

この時、controllerは以下のようなかたちで書けて、authorize_resourceも使えるので一見これでも良さそうです。

foos_controller.rb
FoosController < < ApplicationController
  before_action :set_current_ability
  authorize_resource class: Company

  def xxx
      ...(略)
  end

  private

  def set_current_ability
    @current_ability = Ability.new(current_user, @company) # @current_abilityを上書きする。(@companyは別途定義しているものとします)
  end
end

ただし、この方法だと、Abilityのインスタンス(current_ability)をその都度生成する必要があり、拡張性に欠けます。
indexページなどでよくある、@companies.each do |company| ...のような、ループを回すときに、それぞれのcompanyに対して権限があるかどうかをチェックしたい時に都度Abilityインスタンスを生成することになり、あまり良くありません。
(最初、私はこの方法で実装していたのですがレビューで1番目の方法を教えていただきました。)

0
0
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
0
0