Skip to content

Instantly share code, notes, and snippets.

@stevegeek
Last active September 25, 2023 15:27
Show Gist options
  • Select an option

  • Save stevegeek/513c315ca63620c80c3a7fbef328ba02 to your computer and use it in GitHub Desktop.

Select an option

Save stevegeek/513c315ca63620c80c3a7fbef328ba02 to your computer and use it in GitHub Desktop.
Avo Authorization client for`action_policy`
# frozen_string_literal: true
module Avo
class ActionPolicyAuthorizationClient
include ActionPolicy::Behaviour
def authorize(user, record, action, policy_class: nil)
authorize!(record, to: action, with: policy_class, context: {user: user})
rescue ActionPolicy::NotFound => error
raise NoPolicyError.new error.message
rescue ActionPolicy::Unauthorized => error
raise NotAuthorizedError.new error.message
end
def policy(user, record)
policy_for(record: record, allow_nil: true, context: {user: user})
end
def policy!(user, record)
policy_for(record: record, context: {user: user})
rescue ActionPolicy::NotFound => error
raise NoPolicyError.new error.message
end
def apply_policy(user, model, policy_class: nil)
# Try and figure out the scope from a given policy or auto-detected one
scope_from_policy_class = scope_for_policy_class(policy_class)
# If we discover one use it.
# Else fallback to pundit.
if scope_from_policy_class.present?
scope_from_policy_class.new(user, model).resolve
else
authorized_scope(model, with: policy_class, context: {user: user})
end
rescue ActionPolicy::NotFound => error
raise NoPolicyError.new error.message
end
private
# Fetches the scope for a given policy
def scope_for_policy_class(policy_class = nil)
return if policy_class.blank?
if policy_class.present? && defined?(policy_class::Scope)
policy_class::Scope
end
end
end
end
# frozen_string_literal: true
class ApplicationPolicy < ActionPolicy::Base
# ActionPolicy Policy `initialize` is:
# def initialize(record = nil, **params)
#
# But sometimes Avo calls to create a new Policy with `.new(record, user: user)` & other times with `.new(user, record)`
#
# So modify initialize to support both:
def initialize(record_or_user = nil, record = nil, **options)
user = record ? record_or_user : options[:user]
super(record || record_or_user, user: user)
end
# ...
end
# in avo initializer
config.authorization_client = "Avo::ActionPolicyAuthorizationClient"
@stevegeek
Copy link
Author

You can optionally define some method overrides on ActionPolicyAuthorizationClient too, so you can for example namespace your Avo policies

    def authorization_namespace
      ::Avo
    end

    def default_authorization_policy_class
      ::Avo::NullPolicy
    end

    def authorization_strict_namespace
      true
    end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment