Module: ConcernsOnRails::Controllers::Authorizable

Extended by:
ActiveSupport::Concern
Defined in:
lib/concerns_on_rails/controllers/authorizable.rb

Overview

Declarative, block-only per-action authorization gate. Each rule is a predicate; the first rule that applies to the current action and returns a falsey value halts the request with 403 (rendered via Respondable’s ‘render_error` when available, otherwise an inline envelope).

class Api::BaseController < ApplicationController
  include ConcernsOnRails::Controllers::Authorizable

  authorize_by { current_user.present? }                       # every action
  authorize_by(only: %i[update destroy]) { |_action, user| user.admin? }
  require_role :admin, :editor, only: :publish                 # role sugar
end

The block is invoked with ‘instance_exec` so `current_user` (and any other helper) resolves on the controller. It is arity-safe: write it with zero, one (`|action|`), or two (`|action, user|`) parameters.

Non-goals (kept deliberately small): this is NOT a policy/ability framework. No policy objects, no ability DSL, no resource inference — reach for Pundit or CanCanCan when you outgrow a predicate per action.

Defined Under Namespace

Modules: ClassMethods

Instance Method Summary collapse

Instance Method Details

#authorization_denied(status:, message:) ⇒ Object

Public override point for how a denial is rendered.



88
89
90
91
92
93
94
# File 'lib/concerns_on_rails/controllers/authorizable.rb', line 88

def authorization_denied(status:, message:)
  return unless respond_to?(:response) && response

  return render_error(message: message, status: status, code: "forbidden") if respond_to?(:render_error)

  render json: { success: false, error: { message: message, code: "forbidden" } }, status: status
end

#enforce_authorizationObject

Public so subclasses can override. Iterates the declared rules in order and denies on the first failing rule that applies to the current action.



77
78
79
80
81
82
83
84
85
# File 'lib/concerns_on_rails/controllers/authorizable.rb', line 77

def enforce_authorization
  self.class.authorizable_rules.each do |rule|
    next unless authorization_rule_applies?(rule)
    next if invoke_authorization_check(rule[:check])

    return authorization_denied(status: rule[:status], message: rule[:message])
  end
  nil
end