class Croods::Policy::Scope

Attributes

scope[RW]
tenant[RW]
user[RW]

Public Class Methods

new(tenant:, user:, scope:) click to toggle source
# File lib/croods/policy/scope.rb, line 6
def initialize(tenant:, user:, scope:)
  self.user  = user
  self.scope = scope
  self.tenant = user&.tenant || tenant
end

Public Instance Methods

resolve() click to toggle source
# File lib/croods/policy/scope.rb, line 12
def resolve
  self.scope = tenant_scope(scope) if Croods.multi_tenancy?

  return scope if action.public

  return scope if super?

  return owner_scope(scope) if owner?

  scope
end

Protected Instance Methods

immediate_owner_scope(scope) click to toggle source
# File lib/croods/policy/scope.rb, line 89
def immediate_owner_scope(scope)
  scope.where(user_id: user.id)
end
immediate_owner_scope?(scope) click to toggle source
# File lib/croods/policy/scope.rb, line 93
def immediate_owner_scope?(scope)
  scope.resource.user_is_the_owner? && scope.has_attribute?(:user_id)
end
immediate_tenant_scope(scope) click to toggle source
# File lib/croods/policy/scope.rb, line 62
def immediate_tenant_scope(scope)
  scope.where(Croods.tenant_attribute => tenant.id)
end
immediate_tenant_scope?(scope) click to toggle source
# File lib/croods/policy/scope.rb, line 66
def immediate_tenant_scope?(scope)
  scope.has_attribute?(Croods.tenant_attribute)
end
joins(path) click to toggle source
# File lib/croods/policy/scope.rb, line 52
def joins(path)
  joins = nil

  path.reverse.each do |association|
    joins = joins ? { association.name => joins } : association.name
  end

  joins
end
owner?() click to toggle source
# File lib/croods/policy/scope.rb, line 126
def owner?
  roles.include?(:owner)
end
owner_scope(scope) click to toggle source
# File lib/croods/policy/scope.rb, line 97
def owner_scope(scope)
  return user_owner_scope(scope) if user_owner_scope?(scope)

  return immediate_owner_scope(scope) if immediate_owner_scope?(scope)

  path = reflection_path(scope, :user)
  return scope if path.empty?

  scope.joins(joins(path)).where(
    path.last.plural_name => { user_id: user.id }
  )
end
reflection_path(scope, target, path = []) click to toggle source
# File lib/croods/policy/scope.rb, line 35
def reflection_path(scope, target, path = [])
  return path if scope_is_the_owner?(scope, target)

  associations = scope.reflect_on_all_associations(:belongs_to)

  associations.each do |association|
    next if association.options[:optional]

    model = association.class_name.constantize
    expanded_path = path + [association]
    association_path = reflection_path(model, target, expanded_path)
    return association_path unless association_path.empty?
  end

  []
end
roles() click to toggle source
# File lib/croods/policy/scope.rb, line 118
def roles
  action.roles || DEFAULT_ROLES
end
scope_is_the_owner?(scope, target) click to toggle source
# File lib/croods/policy/scope.rb, line 28
def scope_is_the_owner?(scope, target)
  return scope.reflect_on_association(target) unless target == :user

  scope.resource.user_is_the_owner? &&
    scope.reflect_on_association(target)
end
super?() click to toggle source
# File lib/croods/policy/scope.rb, line 110
def super?
  super_roles.each do |role|
    return true if user&.send("#{role}?")
  end

  false
end
super_roles() click to toggle source
# File lib/croods/policy/scope.rb, line 122
def super_roles
  roles.reject { |role| role == :owner }
end
tenant_scope(scope) click to toggle source
# File lib/croods/policy/scope.rb, line 70
def tenant_scope(scope)
  return immediate_tenant_scope(scope) if immediate_tenant_scope?(scope)

  path = reflection_path(scope, Croods.multi_tenancy_by)
  return scope if path.empty?

  scope.joins(joins(path)).where(
    path.last.plural_name => { Croods.tenant_attribute => tenant.id }
  )
end
user_owner_scope(scope) click to toggle source
# File lib/croods/policy/scope.rb, line 81
def user_owner_scope(scope)
  scope.where(id: user.id)
end
user_owner_scope?(scope) click to toggle source
# File lib/croods/policy/scope.rb, line 85
def user_owner_scope?(scope)
  scope == User || scope.try(:klass) == User
end