From 973b63b396c2a98099caf5eefd1c6841416eddfa Mon Sep 17 00:00:00 2001 From: Alex Emelyanov Date: Sat, 7 Dec 2019 21:57:51 +0300 Subject: [PATCH] Add reason to Pundit::NotAuthorizedError --- README.md | 31 +++++++++++++++++++++++++++++++ lib/pundit.rb | 3 ++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index dc9de43e..26041fbe 100644 --- a/README.md +++ b/README.md @@ -538,6 +538,37 @@ en: Of course, this is just an example. Pundit is agnostic as to how you implement your error messaging. +## Deep error messages customisation + +If you have different authorization deny reasons you want to inform user with descriptive message then: + +In your policy class raise `Pundit::NotAuthorizedError` with custom error message or I18n key in `reason` argument: + +```ruby +class ProjectPolicy < ApplicationPolicy + def create? + if user.has_paid_subscription? + if user.project_limit_reached? + raise Pundit::NotAuthorizedError, reason: 'user.project_limit_reached' + else + true + end + else + raise Pundit::NotAuthorizedError, reason: 'user.paid_subscription_required' + end + end +end +``` + +Then you can get this error message in exception handler: +```ruby +rescue_from Pundit::NotAuthorizedError do |e| + message = e.reason ? I18n.t("errors.#{e.reason}") : e.message + flash[:error] = message, scope: "pundit", default: :default + redirect_to(request.referrer || root_path) +end +``` + ## Manually retrieving policies and scopes Sometimes you want to retrieve a policy for a record outside the controller or diff --git a/lib/pundit.rb b/lib/pundit.rb index c3a1d1da..0b3e31a7 100644 --- a/lib/pundit.rb +++ b/lib/pundit.rb @@ -22,7 +22,7 @@ module Generators; end # Error that will be raised when authorization has failed class NotAuthorizedError < Error - attr_reader :query, :record, :policy + attr_reader :query, :record, :policy, :reason def initialize(options = {}) if options.is_a? String @@ -31,6 +31,7 @@ def initialize(options = {}) @query = options[:query] @record = options[:record] @policy = options[:policy] + @reason = options[:reason] message = options.fetch(:message) { "not allowed to #{query} this #{record.class}" } end