Search code examples
ruby-on-railspunditrolify

How configure pundit to display items belonging to a parent bond


My use case is, if the user have role :agency, he can see clients. But I have to use the link between the client's and agency to verify this. Take a look bellow to see my code:

class Agency < ApplicationRecord
  has_many :agency_clients
  has_many :clients, through: :agency_clients

  resourcify
end

class AgencyClient < ActiveRecord::Base
  belongs_to :agency
  belongs_to :client
end

class Client < ApplicationRecord
  has_many :agency_clients
  has_many :agencies, through: :agency_clients

  resourcify
end


class ClientPolicy < ApplicationPolicy
  def show?
    user.has_role?(:admin) || user.has_role?(:client, record)
  end

  class Scope < Scope
    def resolve
      if user.has_role? :admin
        scope.all
      elsif user.has_role? :client, :any
        scope.with_role(:client, user)
      else
        scope.none
      end
    end
  end
end

Thanks!


Solution

  • This way solved my problem. I hope it helps others.

    My model Agency has many Clients:

    class Agency < ApplicationRecord
      has_many :clients
    
      resourcify
    end
    

    My User have relationships:

    class User < ApplicationRecord
      has_many :users_roles
      has_many :roles, through: :users_roles
      has_many :agencies, through: :roles, source: :resource, source_type: 'Agency'
    
      rolify
    
      ...
    end
    

    Need create the UsersRole model:

    class UsersRole < ApplicationRecord
      belongs_to :user
      belongs_to :role
    end
    

    Finally, my ClientPolicy:

    class ClientPolicy < ApplicationPolicy
      def show?
        user.has_role?(:admin) || user.has_role?(:client, record)
      end
    
      class Scope < Scope
        def resolve
          if user.has_role? :admin
            scope.all
          elsif user.has_role? :client, :any
            scope.with_role(:client, user)
          elsif user.has_role? :agency, :any
            scope.where(agency_id: user.agencies.pluck(:id))
          else
            scope.none
          end
        end
      end
    end