def audit_ability(ability:, action:, subject:) begin ability.authorize!(action, subject) puts "CanCanCan: User has ability to #{action} for #{subject.inspect}" rescue CanCanCan::AccessDenied => exception failed_rules = ability.send(:relevant_rules_for_match, exception.action, exception.subject).reject do |rule| rule.matches_conditions?(exception.action, exception.subject) end if failed_rules.any? puts "CanCanCan::AccessDenied: User does not have ability to #{exception.action} for #{exception.subject.inspect} due to the following conditions:\n" failed_rules.map do |rule| pp { conditions: rule.conditions, block: rule.instance_variable_get(:@block) } puts "" end else puts "CanCanCan::AccessDenied: User does not have ability to #{exception.action} for #{exception.subject.inspect} for indeterminate reasons" end end end user = User.find(...) action = :some_action subject = SomeThing ability = Ability.new(user, ...) audit_ability(ability:, action:, subject:)