removing unauthorized! in favor of authorize! and including more information in AccessDenied exception - closes #40

This commit is contained in:
Ryan Bates
2010-04-16 14:54:18 -07:00
parent ecf2818a9e
commit 8903feee70
12 changed files with 152 additions and 49 deletions

View File

@@ -1,14 +1,6 @@
module CanCan
# A general CanCan exception
class Error < StandardError; end
# This error is raised when a user isn't allowed to access a given
# controller action. See ControllerAdditions#unauthorized! for details.
class AccessDenied < Error; end
end
require 'cancan/ability'
require 'cancan/controller_resource'
require 'cancan/resource_authorization'
require 'cancan/controller_additions'
require 'cancan/active_record_additions'
require 'cancan/exceptions'

View File

@@ -85,7 +85,7 @@ module CanCan
# and ensure the user can perform the current action on it. Under the hood it is doing
# something like the following.
#
# unauthorized! if cannot?(params[:action].to_sym, @article || Article)
# authorize!(params[:action].to_sym, @article || Article)
#
# Call this method directly on the controller class.
#
@@ -116,18 +116,21 @@ module CanCan
base.helper_method :can?, :cannot?
end
# Raises the CanCan::AccessDenied exception. This is often used in a
# controller action to mark a request as unauthorized.
# Raises a CanCan::AccessDenied exception if the current_ability cannot
# perform the given action. This is usually called in a controller action or
# before filter to perform the authorization.
#
# def show
# @article = Article.find(params[:id])
# unauthorized! if cannot? :read, @article
# authorize! :read, @article
# end
#
# The unauthorized! method accepts an optional argument which sets the
# message of the exception.
# A :message option can be passed to specify a different message.
#
# You can rescue from the exception in the controller to define the behavior.
# authorize! :read, @article, :message => "Not authorized to read #{@article.name}"
#
# You can rescue from the exception in the controller to customize how unauthorized
# access is displayed to the user.
#
# class ApplicationController < ActionController::Base
# rescue_from CanCan::AccessDenied do |exception|
@@ -136,10 +139,20 @@ module CanCan
# end
# end
#
# See the load_and_authorize_resource method to automatically add
# the "unauthorized!" behavior to a RESTful controller's actions.
def unauthorized!(message = "You are not authorized to access this page.")
raise AccessDenied, message
# See the CanCan::AccessDenied exception for more details on working with the exception.
#
# See the load_and_authorize_resource method to automatically add the authorize! behavior
# to the default RESTful actions.
def authorize!(action, subject, *args)
message = nil
if args.last.kind_of?(Hash) && args.last.has_key?(:message)
message = args.pop[:message]
end
raise AccessDenied.new(message, action, subject) if cannot?(action, subject, *args)
end
def unauthorized!(message = nil)
raise ImplementationRemoved, "The unauthorized! method has been removed from CanCan, use authorize! instead."
end
# Creates and returns the current user's ability and caches it. If you

View File

@@ -1,7 +1,7 @@
module CanCan
class ControllerResource # :nodoc:
def initialize(controller, name, parent = nil, options = {})
raise CanCan::Error, "The :class option has been renamed to :resource for specifying the class in CanCan." if options.has_key? :class
raise ImplementationRemoved, "The :class option has been renamed to :resource for specifying the class in CanCan." if options.has_key? :class
@controller = controller
@name = name
@parent = parent

43
lib/cancan/exceptions.rb Normal file
View File

@@ -0,0 +1,43 @@
module CanCan
# A general CanCan exception
class Error < StandardError; end
# Raised when removed code is called, an alternative solution is provided in message.
class ImplementationRemoved < Error; end
# This error is raised when a user isn't allowed to access a given controller action.
# This usually happens within a call to ControllerAdditions#authorized! but can be
# raised manually.
#
# raise CanCan::AccessDenied.new("Not authorized!", :read, Article)
#
# The passed message, action, and subject are optional and can later be retrieved when
# rescuing from the exception.
#
# exception.message # => "Not authorized!"
# exception.action # => :read
# exception.subject # => Article
#
# If the message is not specified (or is nil) it will default to "You are anot authorized
# to access this page." This default can be overridden by setting default_message.
#
# exception.default_message = "Default error message"
# exception.message # => "Default error message"
#
# See ControllerAdditions#authorized! for more information on rescuing from this exception.
class AccessDenied < Error
attr_reader :action, :subject
attr_writer :default_message
def initialize(message = nil, action = nil, subject = nil)
@message = message
@action = action
@subject = subject
@default_message = "You are not authorized to access this page."
end
def to_s
@message || @default_message
end
end
end

View File

@@ -1,13 +1,13 @@
Spec::Matchers.define :be_able_to do |*args|
match do |model|
model.can?(*args)
match do |ability|
ability.can?(*args)
end
failure_message_for_should do |model|
failure_message_for_should do |ability|
"expected to be able to #{args.map(&:inspect).join(" ")}"
end
failure_message_for_should_not do |model|
failure_message_for_should_not do |ability|
"expected not to be able to #{args.map(&:inspect).join(" ")}"
end
end

View File

@@ -30,7 +30,7 @@ module CanCan
end
def authorize_resource
@controller.unauthorized! if @controller.cannot?(params[:action].to_sym, resource.model_instance || resource.model_class)
@controller.authorize!(params[:action].to_sym, resource.model_instance || resource.model_class)
end
private