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.

Revisions

  1. stevegeek revised this gist Aug 23, 2023. 1 changed file with 3 additions and 0 deletions.
    3 changes: 3 additions & 0 deletions avo.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,3 @@
    # in avo initializer

    config.authorization_client = "Avo::ActionPolicyAuthorizationClient"
  2. stevegeek created this gist Aug 23, 2023.
    51 changes: 51 additions & 0 deletions action_policy_authorization_client.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,51 @@
    # 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
    16 changes: 16 additions & 0 deletions application_policy.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,16 @@
    # 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