Techioz Blog

cancancan はすべての動的権限を取得します

概要

ID やその他の情報を含むすべての利用可能な権限を API ユーザーに公開する必要がある API を作成しています。

次の構造があります

class User < ApplicationRecord
  has_many :permissions, dependent: :destroy
end

class Permission < ApplicationRecord
  belongs_to :user, dependent: :destroy
end

そして私には能力があります


class Ability
  include CanCan::Ability

  def initialize(user)
    user_permissions(user)
    dynamic_permissions(user)
  end

  def user_permissions(user)
    can :manage, :dashboard if user.admin?
  end

  def dynamic_permissions(user)
    user.permissions.each do |permission|
    #...
      next branch_permissions(permission) if permission.subject_class == 'branch'
    end
  end

  def branch_permissions(permission)
    can permission.action.to_sym, Branch, id: permission.allowed_ids
  end

そして、コントローラーですべての権限を達成したいのですが、=> そのユーザーにできることとできないことです。すでにドキュメントを確認し、#permissions を見つけました。しかし、それはブランチに対して持っている動的アクセス許可では機能しません

したがって、疑似コードを提供して、次のことがカンカンカン方式で行われることを期待しています

  Ability.new(User.find(params[:id]).dynamic_permissions =>
  # {:can=>{:manage=>{"dashboard"=>[]}, :read=>{"Branch"=>['id1', 'id2']}, :index=>{"Branch"=>['id1', 'id2']}, :show=>{"Branch"=>['id1', 'id2']}}, :cannot=>{}}

現在の #permissions cancancan メソッドは、すべての動的評価が欠落している機能ファイルにハードコーディングされた静的アクセス許可のみを返します。

{:can=>{:manage=>{"dashboard"=>[]}, :read=>{"Branch"=>[]}, :index=>{"Branch"=>[]}, :show=>{"Branch"=>[]}}, :cannot=>{}}

これらすべてを取得するカスタム メソッドを変更して作成できることはわかっていますが、これを実現するためにどのようなアプローチが受け入れられているのか疑問に思っています。

解決策

わかりました、実際は簡単でした。情報源を読んだことが役に立ちました。

  def branch_permissions(permission)
    can permission.action.to_sym, Branch, id: permission.allowed_ids
  end

このコードは次のように変更する必要があります

  def branch_permissions(permission)
    can permission.action.to_sym, Branch, id: permission.allowed_ids.map(&:to_sym)
  end

このメソッド parse_attributes_from_extra_args は、シンボルを内部状態の属性として扱い、アクセス許可でこれを期待どおりに表示します。これらのシンボルを文字列にシリアル化してから、

#  Ability.new(User.find(params[:id]).permissions
=> {:can=>{:manage=>{"dashboard"=>[]}, :read=>{"Branch"=>[:id1, :id2]}, :index=>{"Branch"=>['id1', 'id2']}, :show=>{"Branch"=>[:id1', :id2]}}, :cannot=>{}}