cancancanのgemのソースコードを読んでいたら、発見があったので記事にします。
できること
Ability
クラスでの権限設定で、継承元のクラスを指定すると子クラスの権限設定も行われます。
コード例
例えば以下のように書くと、ApplicationRecord
を継承しているクラス全体に適用することができます。
books_controller
class BooksController < ApplicationController
before_action -> { authorize! :read, Book }
# ...略
end
ability.rb
class Ability
include CanCan::Ability
def initialize(user)
can :manage, ApplicationRecord
end
end
該当コード
def possible_relevant_rules(subject)
if subject.is_a?(Hash)
rules
else
# チェックしたい対象のリソースと関連するルール(abilityクラスに記載されているもの)を探すメソッド内で、
# alternative_subjectsというのが呼ばれています。
positions = @rules_index.values_at(subject, *alternative_subjects(subject))
positions.compact!
positions.flatten!
positions.sort!
positions.map { |i| @rules[i] }
end
end
gems/cancancan-3.5.0/lib/cancan/ability.rb
def alternative_subjects(subject)
subject = subject.class unless subject.is_a?(Module)
if subject.respond_to?(:subclasses) && defined?(ActiveRecord::Base) && subject < ActiveRecord::Base
[:all, *(subject.ancestors + subject.subclasses), subject.class.to_s] # ここで継承元クラスを取得しています
else
[:all, *subject.ancestors, subject.class.to_s]
end
end
さいごに
逆に言えば、継承先までは許可したくない場合(ケースとしてあるかわかりませんが)は、明示的にcannot
を使う必要がありそうです。