Skip to content

Instantly share code, notes, and snippets.

@glaszig
Last active March 30, 2026 19:04
Show Gist options
  • Select an option

  • Save glaszig/1e5118eaab4f633ff0c2e17ef706345d to your computer and use it in GitHub Desktop.

Select an option

Save glaszig/1e5118eaab4f633ff0c2e17ef706345d to your computer and use it in GitHub Desktop.
ruby authorization policies in 40 lines of code in spirit of rails-native authentication
# app/controllers/concerns/authorization.rb
#
# use this mixin:
#
# class ApplicationController < ActionController::Base
# include Authorization
# end
#
# query policy in views:
#
# can? :edit, appointment
#
module Authorization
extend ActiveSupport::Concern
Error = Class.new(RuntimeError)
included do
helper_method :can?, :policy_scope
end
class_methods do
def require_authorization
after_action { raise Error, self.class unless @_authorized }
end
end
def authorize object
raise Error, "Not authorized" unless can? action_name, object
@_authorized = true
object
end
def can? action, subject
gate = find_policy_class(subject).method "#{action}?"
gate.arity == 0 ? gate.call : gate.call(subject)
rescue NameError => e
raise Error, e.message, cause: e
end
def policy_scope subject
find_policy_class(subject, suffix: "Policy::Scope").resolve subject
end
private
def find_policy_class subject, suffix: "Policy"
class_name = subject.respond_to?(:model_name) ? subject.model_name : subject.class.name
policy = "#{class_name}#{suffix}".constantize.new
rescue NameError => e
raise Error, "Policy class #{e.name} not found"
end
end
# app/policies/appointment_policy.rb
class AppointmentPolicy
class Scope
def resolve scope
if Current.user.admin?
scope
else
scope.mine
end
end
end
def edit? appointment
return false if appointment.participant_approved?
return true if Current.user.admin?
appointment.user == Current.user && !appointment.review
end
def destroy? appointment
!appointment.participant_approved?
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment