adding :through option to replace :nesting option and moving ResourceAuthorization class code into ControllerResource
This commit is contained in:
		
							parent
							
								
									8dee01195d
								
							
						
					
					
						commit
						25a1c553bf
					
				@ -1,3 +1,9 @@
 | 
				
			|||||||
 | 
					* Changing :resource option in load/authorize_resource back to :class with ability to pass false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* Removing :nested option in favor of :through option with separate load/authorize call
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* Moving internal logic from ResourceAuthorization to ControllerResource class
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* Supporting multiple "can" and "cannot" calls with accessible_by (thanks funny-falcon) - see issue #71
 | 
					* Supporting multiple "can" and "cannot" calls with accessible_by (thanks funny-falcon) - see issue #71
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* Supporting deeply nested aliases - see issue #98
 | 
					* Supporting deeply nested aliases - see issue #98
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,6 @@
 | 
				
			|||||||
require 'cancan/ability'
 | 
					require 'cancan/ability'
 | 
				
			||||||
require 'cancan/can_definition'
 | 
					require 'cancan/can_definition'
 | 
				
			||||||
require 'cancan/controller_resource'
 | 
					require 'cancan/controller_resource'
 | 
				
			||||||
require 'cancan/resource_authorization'
 | 
					 | 
				
			||||||
require 'cancan/controller_additions'
 | 
					require 'cancan/controller_additions'
 | 
				
			||||||
require 'cancan/active_record_additions'
 | 
					require 'cancan/active_record_additions'
 | 
				
			||||||
require 'cancan/exceptions'
 | 
					require 'cancan/exceptions'
 | 
				
			||||||
 | 
				
			|||||||
@ -11,11 +11,11 @@ module CanCan
 | 
				
			|||||||
      #     load_and_authorize_resource
 | 
					      #     load_and_authorize_resource
 | 
				
			||||||
      #   end
 | 
					      #   end
 | 
				
			||||||
      #
 | 
					      #
 | 
				
			||||||
      def load_and_authorize_resource(options = {})
 | 
					      def load_and_authorize_resource(*args)
 | 
				
			||||||
        ResourceAuthorization.add_before_filter(self, :load_and_authorize_resource, options)
 | 
					        ControllerResource.add_before_filter(self, :load_and_authorize_resource, *args)
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      # Sets up a before filter which loads the appropriate model resource into an instance variable.
 | 
					      # Sets up a before filter which loads the model resource into an instance variable.
 | 
				
			||||||
      # For example, given an ArticlesController it will load the current article into the @article
 | 
					      # For example, given an ArticlesController it will load the current article into the @article
 | 
				
			||||||
      # instance variable. It does this by either calling Article.find(params[:id]) or
 | 
					      # instance variable. It does this by either calling Article.find(params[:id]) or
 | 
				
			||||||
      # Article.new(params[:article]) depending upon the action. It does nothing for the "index"
 | 
					      # Article.new(params[:article]) depending upon the action. It does nothing for the "index"
 | 
				
			||||||
@ -41,6 +41,20 @@ module CanCan
 | 
				
			|||||||
      #     end
 | 
					      #     end
 | 
				
			||||||
      #   end
 | 
					      #   end
 | 
				
			||||||
      #
 | 
					      #
 | 
				
			||||||
 | 
					      # If a name is provided which does not match the controller it assumes it is a parent resource. Child
 | 
				
			||||||
 | 
					      # resources can then be loaded through it.
 | 
				
			||||||
 | 
					      #
 | 
				
			||||||
 | 
					      #   class BooksController < ApplicationController
 | 
				
			||||||
 | 
					      #     load_resource :author
 | 
				
			||||||
 | 
					      #     load_resource :book, :through => :author
 | 
				
			||||||
 | 
					      #   end
 | 
				
			||||||
 | 
					      #
 | 
				
			||||||
 | 
					      # Here the author resource will be loaded before each action using params[:author_id]. The book resource
 | 
				
			||||||
 | 
					      # will then be loaded through the @author instance variable.
 | 
				
			||||||
 | 
					      #
 | 
				
			||||||
 | 
					      # That first argument is optional and will default to the singular name of the controller.
 | 
				
			||||||
 | 
					      # A hash of options (see below) can also be passed to this method to further customize it.
 | 
				
			||||||
 | 
					      #
 | 
				
			||||||
      # See load_and_authorize_resource to automatically authorize the resource too.
 | 
					      # See load_and_authorize_resource to automatically authorize the resource too.
 | 
				
			||||||
      #
 | 
					      #
 | 
				
			||||||
      # Options:
 | 
					      # Options:
 | 
				
			||||||
@ -50,27 +64,22 @@ module CanCan
 | 
				
			|||||||
      # [:+except+]
 | 
					      # [:+except+]
 | 
				
			||||||
      #   Does not apply before filter to given actions.
 | 
					      #   Does not apply before filter to given actions.
 | 
				
			||||||
      #
 | 
					      #
 | 
				
			||||||
      # [:+nested+]
 | 
					      # [:+through+]
 | 
				
			||||||
      #   Specify which resource this is nested under.
 | 
					      #   Load this resource through another one. This should match the name of the parent instance variable.
 | 
				
			||||||
      #
 | 
					      #
 | 
				
			||||||
      #     load_resource :nested => :author
 | 
					      # [:+parent+]
 | 
				
			||||||
 | 
					      #   True or false depending on if the resource is considered a parent resource. This defaults to +true+ if a resource
 | 
				
			||||||
 | 
					      #   name is given which does not match the controller.
 | 
				
			||||||
      #
 | 
					      #
 | 
				
			||||||
      #   Deep nesting can be defined in an array.
 | 
					      # [:+class+]
 | 
				
			||||||
      #
 | 
					 | 
				
			||||||
      #     load_resource :nested => [:publisher, :author]
 | 
					 | 
				
			||||||
      #
 | 
					 | 
				
			||||||
      # [:+name+]
 | 
					 | 
				
			||||||
      #   The name of the resource if it cannot be determined from controller (string or symbol).
 | 
					 | 
				
			||||||
      #
 | 
					 | 
				
			||||||
      #     load_resource :name => :article
 | 
					 | 
				
			||||||
      #
 | 
					 | 
				
			||||||
      # [:+resource+]
 | 
					 | 
				
			||||||
      #   The class to use for the model (string or constant).
 | 
					      #   The class to use for the model (string or constant).
 | 
				
			||||||
      #
 | 
					      #
 | 
				
			||||||
 | 
					      # [:+instance_name+]
 | 
				
			||||||
 | 
					      #   The name of the instance variable to load the resource into.
 | 
				
			||||||
 | 
					      #
 | 
				
			||||||
      # [:+collection+]
 | 
					      # [:+collection+]
 | 
				
			||||||
      #   Specify which actions are resource collection actions in addition to :+index+. This
 | 
					      #   Specify which actions are resource collection actions in addition to :+index+. This
 | 
				
			||||||
      #   is usually not necessary because it will try to guess depending on if an :+id+
 | 
					      #   is usually not necessary because it will try to guess depending on if the id param is present.
 | 
				
			||||||
      #   is present in +params+.
 | 
					 | 
				
			||||||
      #
 | 
					      #
 | 
				
			||||||
      #     load_resource :collection => [:sort, :list]
 | 
					      #     load_resource :collection => [:sort, :list]
 | 
				
			||||||
      #
 | 
					      #
 | 
				
			||||||
@ -81,11 +90,11 @@ module CanCan
 | 
				
			|||||||
      #
 | 
					      #
 | 
				
			||||||
      #     load_resource :new => :build
 | 
					      #     load_resource :new => :build
 | 
				
			||||||
      #
 | 
					      #
 | 
				
			||||||
      def load_resource(options = {})
 | 
					      def load_resource(*args)
 | 
				
			||||||
        ResourceAuthorization.add_before_filter(self, :load_resource, options)
 | 
					        ControllerResource.add_before_filter(self, :load_resource, *args)
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      # Sets up a before filter which authorizes the current resource using the instance variable.
 | 
					      # Sets up a before filter which authorizes the resource using the instance variable.
 | 
				
			||||||
      # For example, if you have an ArticlesController it will check the @article instance variable
 | 
					      # For example, if you have an ArticlesController it will check the @article instance variable
 | 
				
			||||||
      # and ensure the user can perform the current action on it. Under the hood it is doing
 | 
					      # and ensure the user can perform the current action on it. Under the hood it is doing
 | 
				
			||||||
      # something like the following.
 | 
					      # something like the following.
 | 
				
			||||||
@ -98,6 +107,19 @@ module CanCan
 | 
				
			|||||||
      #     authorize_resource
 | 
					      #     authorize_resource
 | 
				
			||||||
      #   end
 | 
					      #   end
 | 
				
			||||||
      #
 | 
					      #
 | 
				
			||||||
 | 
					      # If you pass in the name of a resource which does not match the controller it will assume
 | 
				
			||||||
 | 
					      # it is a parent resource.
 | 
				
			||||||
 | 
					      #
 | 
				
			||||||
 | 
					      #   class BooksController < ApplicationController
 | 
				
			||||||
 | 
					      #     authorize_resource :author
 | 
				
			||||||
 | 
					      #     authorize_resource :book
 | 
				
			||||||
 | 
					      #   end
 | 
				
			||||||
 | 
					      #
 | 
				
			||||||
 | 
					      # Here it will authorize :+show+, @+author+ on every action before authorizing the book.
 | 
				
			||||||
 | 
					      #
 | 
				
			||||||
 | 
					      # That first argument is optional and will default to the singular name of the controller.
 | 
				
			||||||
 | 
					      # A hash of options (see below) can also be passed to this method to further customize it.
 | 
				
			||||||
 | 
					      #
 | 
				
			||||||
      # See load_and_authorize_resource to automatically load the resource too.
 | 
					      # See load_and_authorize_resource to automatically load the resource too.
 | 
				
			||||||
      #
 | 
					      #
 | 
				
			||||||
      # Options:
 | 
					      # Options:
 | 
				
			||||||
@ -107,17 +129,23 @@ module CanCan
 | 
				
			|||||||
      # [:+except+]
 | 
					      # [:+except+]
 | 
				
			||||||
      #   Does not apply before filter to given actions.
 | 
					      #   Does not apply before filter to given actions.
 | 
				
			||||||
      #
 | 
					      #
 | 
				
			||||||
      # [:+name+]
 | 
					      # [:+parent+]
 | 
				
			||||||
      #   The name of the resource if it cannot be determined from controller (string or symbol).
 | 
					      #   True or false depending on if the resource is considered a parent resource. This defaults to +true+ if a resource
 | 
				
			||||||
 | 
					      #   name is given which does not match the controller.
 | 
				
			||||||
      #
 | 
					      #
 | 
				
			||||||
      #     load_resource :name => :article
 | 
					      # [:+class+]
 | 
				
			||||||
 | 
					      #   The class to use for the model (string or constant). This passed in when the instance variable is not set.
 | 
				
			||||||
 | 
					      #   Pass +false+ if there is no associated class for this resource and it will use a symbol of the resource name.
 | 
				
			||||||
 | 
					      #
 | 
				
			||||||
 | 
					      # [:+instance_name+]
 | 
				
			||||||
 | 
					      #   The name of the instance variable for this resource.
 | 
				
			||||||
      #
 | 
					      #
 | 
				
			||||||
      # [:+resource+]
 | 
					      # [:+resource+]
 | 
				
			||||||
      #   The class to use for the model (string or constant). Alternatively pass a symbol
 | 
					      #   The class to use for the model (string or constant). Alternatively pass a symbol
 | 
				
			||||||
      #   to represent a resource which does not have a class.
 | 
					      #   to represent a resource which does not have a class.
 | 
				
			||||||
      #
 | 
					      #
 | 
				
			||||||
      def authorize_resource(options = {})
 | 
					      def authorize_resource(*args)
 | 
				
			||||||
        ResourceAuthorization.add_before_filter(self, :authorize_resource, options)
 | 
					        ControllerResource.add_before_filter(self, :authorize_resource, *args)
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,54 +1,105 @@
 | 
				
			|||||||
module CanCan
 | 
					module CanCan
 | 
				
			||||||
  # Used internally to load and authorize a given controller resource.
 | 
					  # Handle the load and authorization controller logic so we don't clutter up all controllers with non-interface methods.
 | 
				
			||||||
  # This manages finding or building an instance of the resource. If a
 | 
					  # This class is used internally, so you do not need to call methods directly on it.
 | 
				
			||||||
  # parent is given it will go through the association.
 | 
					 | 
				
			||||||
  class ControllerResource # :nodoc:
 | 
					  class ControllerResource # :nodoc:
 | 
				
			||||||
    def initialize(controller, name, parent = nil, options = {})
 | 
					    def self.add_before_filter(controller_class, method, options = {})
 | 
				
			||||||
      raise ImplementationRemoved, "The :class option has been renamed to :resource for specifying the class in CanCan." if options.has_key? :class
 | 
					      controller_class.before_filter(options.slice(:only, :except)) do |controller|
 | 
				
			||||||
      @controller = controller
 | 
					        ControllerResource.new(controller, controller.params, options.except(:only, :except)).send(method)
 | 
				
			||||||
      @name = name
 | 
					 | 
				
			||||||
      @parent = parent
 | 
					 | 
				
			||||||
      @options = options
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # Returns the class used for this resource. This can be overriden by the :resource option.
 | 
					 | 
				
			||||||
    # Sometimes one will use a symbol as the resource if a class does not exist for it. In that
 | 
					 | 
				
			||||||
    # case "find" and "build" should not be called on it.
 | 
					 | 
				
			||||||
    def model_class
 | 
					 | 
				
			||||||
      resource_class = @options[:resource]
 | 
					 | 
				
			||||||
      if resource_class.nil?
 | 
					 | 
				
			||||||
        @name.to_s.camelize.constantize
 | 
					 | 
				
			||||||
      elsif resource_class.kind_of? String
 | 
					 | 
				
			||||||
        resource_class.constantize
 | 
					 | 
				
			||||||
      else
 | 
					 | 
				
			||||||
        resource_class # could be a symbol
 | 
					 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def find(id)
 | 
					    def initialize(controller, params, *args)
 | 
				
			||||||
      self.model_instance ||= base.find(id)
 | 
					      @controller = controller
 | 
				
			||||||
 | 
					      @params = params
 | 
				
			||||||
 | 
					      @options = args.extract_options!
 | 
				
			||||||
 | 
					      @name = args.first
 | 
				
			||||||
 | 
					      raise CanCan::ImplementationRemoved, "The :nested option is no longer supported, instead use :through with separate load/authorize call." if @options[:nested]
 | 
				
			||||||
 | 
					      raise CanCan::ImplementationRemoved, "The :name option is no longer supported, instead pass the name as the first argument." if @options[:name]
 | 
				
			||||||
 | 
					      raise CanCan::ImplementationRemoved, "The :resource option has been renamed back to :class, use false if no class." if @options[:resource]
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Build a new instance of this resource. If it is a class we just call "new" otherwise
 | 
					    def load_and_authorize_resource
 | 
				
			||||||
    # it's an associaiton and "build" is used.
 | 
					      load_resource
 | 
				
			||||||
    def build(attributes)
 | 
					      authorize_resource
 | 
				
			||||||
      self.model_instance ||= (base.kind_of?(Class) ? base.new(attributes) : base.build(attributes))
 | 
					 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def model_instance
 | 
					    def load_resource
 | 
				
			||||||
      @controller.instance_variable_get("@#{@name}")
 | 
					      if !resource_instance && (parent? || member_action?)
 | 
				
			||||||
 | 
					        @controller.instance_variable_set("@#{name}", load_resource_instance)
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def model_instance=(instance)
 | 
					    def authorize_resource
 | 
				
			||||||
      @controller.instance_variable_set("@#{@name}", instance)
 | 
					      @controller.authorize!(@params[:action].to_sym, resource_instance || resource_class)
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def parent?
 | 
				
			||||||
 | 
					      @options[:parent] || @name && @name != name_from_controller.to_sym
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private
 | 
					    private
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def load_resource_instance
 | 
				
			||||||
 | 
					      if !parent? && new_actions.include?(@params[:action].to_sym)
 | 
				
			||||||
 | 
					        resource_base.kind_of?(Class) ? resource_base.new(attributes) : resource_base.build(attributes)
 | 
				
			||||||
 | 
					      elsif id_param
 | 
				
			||||||
 | 
					        resource_base.find(id_param)
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def attributes
 | 
				
			||||||
 | 
					      @params[name.to_sym]
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def id_param
 | 
				
			||||||
 | 
					      @params[parent? ? :"#{name}_id" : :id]
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def member_action?
 | 
				
			||||||
 | 
					      !collection_actions.include? @params[:action].to_sym
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Returns the class used for this resource. This can be overriden by the :class option.
 | 
				
			||||||
 | 
					    # If +false+ is passed in it will use the resource name as a symbol in which case it should
 | 
				
			||||||
 | 
					    # only be used for authorization, not loading since there's no class to load through.
 | 
				
			||||||
 | 
					    def resource_class
 | 
				
			||||||
 | 
					      case @options[:class]
 | 
				
			||||||
 | 
					      when false  then name.to_sym
 | 
				
			||||||
 | 
					      when nil    then name.to_s.camelize.constantize
 | 
				
			||||||
 | 
					      when String then @options[:class].constantize
 | 
				
			||||||
 | 
					      else @options[:class]
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def resource_instance
 | 
				
			||||||
 | 
					      @controller.instance_variable_get("@#{name}")
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # The object that methods (such as "find", "new" or "build") are called on.
 | 
					    # The object that methods (such as "find", "new" or "build") are called on.
 | 
				
			||||||
    # If there is a parent it will be the association, otherwise it will be the model's class.
 | 
					    # If the :through option is passed it will go through an association on that instance.
 | 
				
			||||||
    def base
 | 
					    def resource_base
 | 
				
			||||||
      @parent ? @parent.model_instance.send(@name.to_s.pluralize) : model_class
 | 
					      through_resource ? through_resource.send(name.to_s.pluralize) : resource_class
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # The object to load this resource through.
 | 
				
			||||||
 | 
					    def through_resource
 | 
				
			||||||
 | 
					      @options[:through] && @controller.instance_variable_get("@#{@options[:through]}")
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def name
 | 
				
			||||||
 | 
					      @name || name_from_controller
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def name_from_controller
 | 
				
			||||||
 | 
					      @params[:controller].sub("Controller", "").underscore.split('/').last.singularize
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def collection_actions
 | 
				
			||||||
 | 
					      [:index] + [@options[:collection]].flatten
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def new_actions
 | 
				
			||||||
 | 
					      [:new, :create] + [@options[:new]].flatten
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
				
			|||||||
@ -1,70 +0,0 @@
 | 
				
			|||||||
module CanCan
 | 
					 | 
				
			||||||
  # Handle the load and authorization controller logic so we don't clutter up all controllers with non-interface methods.
 | 
					 | 
				
			||||||
  # This class is used internally, so you do not need to call methods directly on it.
 | 
					 | 
				
			||||||
  class ResourceAuthorization # :nodoc:
 | 
					 | 
				
			||||||
    def self.add_before_filter(controller_class, method, options = {})
 | 
					 | 
				
			||||||
      controller_class.before_filter(options.slice(:only, :except)) do |controller|
 | 
					 | 
				
			||||||
        ResourceAuthorization.new(controller, controller.params, options.except(:only, :except)).send(method)
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def initialize(controller, params, options = {})
 | 
					 | 
				
			||||||
      @controller = controller
 | 
					 | 
				
			||||||
      @params = params
 | 
					 | 
				
			||||||
      @options = options
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def load_and_authorize_resource
 | 
					 | 
				
			||||||
      load_resource
 | 
					 | 
				
			||||||
      authorize_resource
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def load_resource
 | 
					 | 
				
			||||||
      if collection_actions.include? @params[:action].to_sym
 | 
					 | 
				
			||||||
        parent_resource
 | 
					 | 
				
			||||||
      else
 | 
					 | 
				
			||||||
        if new_actions.include? @params[:action].to_sym
 | 
					 | 
				
			||||||
          resource.build(@params[model_name.to_sym])
 | 
					 | 
				
			||||||
        elsif @params[:id]
 | 
					 | 
				
			||||||
          resource.find(@params[:id])
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def authorize_resource
 | 
					 | 
				
			||||||
      @controller.authorize!(@params[:action].to_sym, resource.model_instance || resource.model_class)
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def resource
 | 
					 | 
				
			||||||
      @resource ||= ControllerResource.new(@controller, model_name, parent_resource, @options)
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def parent_resource
 | 
					 | 
				
			||||||
      parent = nil
 | 
					 | 
				
			||||||
      [@options[:nested]].flatten.compact.each do |name|
 | 
					 | 
				
			||||||
        id = @params["#{name}_id".to_sym]
 | 
					 | 
				
			||||||
        if id
 | 
					 | 
				
			||||||
          parent = ControllerResource.new(@controller, name, parent)
 | 
					 | 
				
			||||||
          parent.find(id)
 | 
					 | 
				
			||||||
        else
 | 
					 | 
				
			||||||
          parent = nil
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
      parent
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def model_name
 | 
					 | 
				
			||||||
      @options[:name] || @params[:controller].sub("Controller", "").underscore.split('/').last.singularize
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def collection_actions
 | 
					 | 
				
			||||||
      [:index] + [@options[:collection]].flatten
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def new_actions
 | 
					 | 
				
			||||||
      [:new, :create] + [@options[:new]].flatten
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
end
 | 
					 | 
				
			||||||
@ -52,20 +52,20 @@ describe CanCan::ControllerAdditions do
 | 
				
			|||||||
    @controller.cannot?(:foo, :bar).should be_true
 | 
					    @controller.cannot?(:foo, :bar).should be_true
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  it "load_and_authorize_resource should setup a before filter which passes call to ResourceAuthorization" do
 | 
					  it "load_and_authorize_resource should setup a before filter which passes call to ControllerResource" do
 | 
				
			||||||
    stub(CanCan::ResourceAuthorization).new(@controller, @controller.params, :foo => :bar).mock!.load_and_authorize_resource
 | 
					    stub(CanCan::ControllerResource).new(@controller, @controller.params, :foo => :bar).mock!.load_and_authorize_resource
 | 
				
			||||||
    mock(@controller_class).before_filter({}) { |options, block| block.call(@controller) }
 | 
					    mock(@controller_class).before_filter({}) { |options, block| block.call(@controller) }
 | 
				
			||||||
    @controller_class.load_and_authorize_resource :foo => :bar
 | 
					    @controller_class.load_and_authorize_resource :foo => :bar
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  it "authorize_resource should setup a before filter which passes call to ResourceAuthorization" do
 | 
					  it "authorize_resource should setup a before filter which passes call to ControllerResource" do
 | 
				
			||||||
    stub(CanCan::ResourceAuthorization).new(@controller, @controller.params, :foo => :bar).mock!.authorize_resource
 | 
					    stub(CanCan::ControllerResource).new(@controller, @controller.params, :foo => :bar).mock!.authorize_resource
 | 
				
			||||||
    mock(@controller_class).before_filter(:except => :show) { |options, block| block.call(@controller) }
 | 
					    mock(@controller_class).before_filter(:except => :show) { |options, block| block.call(@controller) }
 | 
				
			||||||
    @controller_class.authorize_resource :foo => :bar, :except => :show
 | 
					    @controller_class.authorize_resource :foo => :bar, :except => :show
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  it "load_resource should setup a before filter which passes call to ResourceAuthorization" do
 | 
					  it "load_resource should setup a before filter which passes call to ControllerResource" do
 | 
				
			||||||
    stub(CanCan::ResourceAuthorization).new(@controller, @controller.params, :foo => :bar).mock!.load_resource
 | 
					    stub(CanCan::ControllerResource).new(@controller, @controller.params, :foo => :bar).mock!.load_resource
 | 
				
			||||||
    mock(@controller_class).before_filter(:only => [:show, :index]) { |options, block| block.call(@controller) }
 | 
					    mock(@controller_class).before_filter(:only => [:show, :index]) { |options, block| block.call(@controller) }
 | 
				
			||||||
    @controller_class.load_resource :foo => :bar, :only => [:show, :index]
 | 
					    @controller_class.load_resource :foo => :bar, :only => [:show, :index]
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
				
			|||||||
@ -2,58 +2,170 @@ require "spec_helper"
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
describe CanCan::ControllerResource do
 | 
					describe CanCan::ControllerResource do
 | 
				
			||||||
  before(:each) do
 | 
					  before(:each) do
 | 
				
			||||||
    @controller = Object.new
 | 
					    @controller = Object.new # simple stub for now
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  it "should determine model class by constantizing give name" do
 | 
					  it "should load the resource into an instance variable if params[:id] is specified" do
 | 
				
			||||||
    CanCan::ControllerResource.new(@controller, :ability).model_class.should == Ability
 | 
					    stub(Ability).find(123) { :some_resource }
 | 
				
			||||||
  end
 | 
					    resource = CanCan::ControllerResource.new(@controller, :controller => "abilities", :action => "show", :id => 123)
 | 
				
			||||||
 | 
					    resource.load_resource
 | 
				
			||||||
  it "should fetch model through model class and assign it to the instance" do
 | 
					 | 
				
			||||||
    stub(Ability).find(123) { :some_ability }
 | 
					 | 
				
			||||||
    CanCan::ControllerResource.new(@controller, :ability).find(123)
 | 
					 | 
				
			||||||
    @controller.instance_variable_get(:@ability).should == :some_ability
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it "should fetch model through parent and assign it to the instance" do
 | 
					 | 
				
			||||||
    parent = Object.new
 | 
					 | 
				
			||||||
    stub(parent).model_instance.stub!.abilities.stub!.find(123) { :some_ability }
 | 
					 | 
				
			||||||
    CanCan::ControllerResource.new(@controller, :ability, parent).find(123)
 | 
					 | 
				
			||||||
    @controller.instance_variable_get(:@ability).should == :some_ability
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it "should build model through model class and assign it to the instance" do
 | 
					 | 
				
			||||||
    stub(Ability).new(123) { :some_ability }
 | 
					 | 
				
			||||||
    CanCan::ControllerResource.new(@controller, :ability).build(123)
 | 
					 | 
				
			||||||
    @controller.instance_variable_get(:@ability).should == :some_ability
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it "should build model through parent and assign it to the instance" do
 | 
					 | 
				
			||||||
    parent = Object.new
 | 
					 | 
				
			||||||
    stub(parent).model_instance.stub!.abilities.stub!.build(123) { :some_ability }
 | 
					 | 
				
			||||||
    CanCan::ControllerResource.new(@controller, :ability, parent).build(123)
 | 
					 | 
				
			||||||
    @controller.instance_variable_get(:@ability).should == :some_ability
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it "should not load resource if instance variable is already provided" do
 | 
					 | 
				
			||||||
    @controller.instance_variable_set(:@ability, :some_ability)
 | 
					 | 
				
			||||||
    CanCan::ControllerResource.new(@controller, :ability).find(123)
 | 
					 | 
				
			||||||
    @controller.instance_variable_get(:@ability).should == :some_ability
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it "should use the model class option if provided" do
 | 
					 | 
				
			||||||
    stub(Person).find(123) { :some_resource }
 | 
					 | 
				
			||||||
    CanCan::ControllerResource.new(@controller, :ability, nil, :resource => Person).find(123)
 | 
					 | 
				
			||||||
    @controller.instance_variable_get(:@ability).should == :some_resource
 | 
					    @controller.instance_variable_get(:@ability).should == :some_resource
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  it "should convert string to constant for resource" do
 | 
					  it "should not load resource into an instance variable if already set" do
 | 
				
			||||||
    CanCan::ControllerResource.new(@controller, :ability, nil, :resource => "Person").model_class.should == Person
 | 
					    @controller.instance_variable_set(:@ability, :some_ability)
 | 
				
			||||||
 | 
					    resource = CanCan::ControllerResource.new(@controller, :controller => "abilities", :action => "show", :id => 123)
 | 
				
			||||||
 | 
					    resource.load_resource
 | 
				
			||||||
 | 
					    @controller.instance_variable_get(:@ability).should == :some_ability
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  it "should raise an exception when specifying :class option since it is no longer used" do
 | 
					  it "should properly load resource for namespaced controller" do
 | 
				
			||||||
 | 
					    stub(Ability).find(123) { :some_resource }
 | 
				
			||||||
 | 
					    resource = CanCan::ControllerResource.new(@controller, :controller => "admin/abilities", :action => "show", :id => 123)
 | 
				
			||||||
 | 
					    resource.load_resource
 | 
				
			||||||
 | 
					    @controller.instance_variable_get(:@ability).should == :some_resource
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it "should properly load resource for namespaced controller when using '::' for namespace" do
 | 
				
			||||||
 | 
					    stub(Ability).find(123) { :some_resource }
 | 
				
			||||||
 | 
					    resource = CanCan::ControllerResource.new(@controller, :controller => "Admin::AbilitiesController", :action => "show", :id => 123)
 | 
				
			||||||
 | 
					    resource.load_resource
 | 
				
			||||||
 | 
					    @controller.instance_variable_get(:@ability).should == :some_resource
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it "should build a new resource with hash if params[:id] is not specified" do
 | 
				
			||||||
 | 
					    stub(Ability).new(:foo => "bar") { :some_resource }
 | 
				
			||||||
 | 
					    resource = CanCan::ControllerResource.new(@controller, :controller => "abilities", :action => "create", :ability => {:foo => "bar"})
 | 
				
			||||||
 | 
					    resource.load_resource
 | 
				
			||||||
 | 
					    @controller.instance_variable_get(:@ability).should == :some_resource
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it "should build a new resource even if attribute hash isn't specified" do
 | 
				
			||||||
 | 
					    stub(Ability).new(nil) { :some_resource }
 | 
				
			||||||
 | 
					    resource = CanCan::ControllerResource.new(@controller, :controller => "abilities", :action => "new")
 | 
				
			||||||
 | 
					    resource.load_resource
 | 
				
			||||||
 | 
					    @controller.instance_variable_get(:@ability).should == :some_resource
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it "should not build a resource when on index action" do
 | 
				
			||||||
 | 
					    resource = CanCan::ControllerResource.new(@controller, :controller => "abilities", :action => "index")
 | 
				
			||||||
 | 
					    resource.load_resource
 | 
				
			||||||
 | 
					    @controller.instance_variable_get(:@ability).should be_nil
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it "should perform authorization using controller action and loaded model" do
 | 
				
			||||||
 | 
					    @controller.instance_variable_set(:@ability, :some_resource)
 | 
				
			||||||
 | 
					    stub(@controller).authorize!(:show, :some_resource) { raise CanCan::AccessDenied }
 | 
				
			||||||
 | 
					    resource = CanCan::ControllerResource.new(@controller, :controller => "abilities", :action => "show")
 | 
				
			||||||
 | 
					    lambda { resource.authorize_resource }.should raise_error(CanCan::AccessDenied)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it "should perform authorization using controller action and non loaded model" do
 | 
				
			||||||
 | 
					    stub(@controller).authorize!(:show, Ability) { raise CanCan::AccessDenied }
 | 
				
			||||||
 | 
					    resource = CanCan::ControllerResource.new(@controller, :controller => "abilities", :action => "show")
 | 
				
			||||||
 | 
					    lambda { resource.authorize_resource }.should raise_error(CanCan::AccessDenied)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it "should call load_resource and authorize_resource for load_and_authorize_resource" do
 | 
				
			||||||
 | 
					    resource = CanCan::ControllerResource.new(@controller, :controller => "abilities", :action => "show")
 | 
				
			||||||
 | 
					    mock(resource).load_resource
 | 
				
			||||||
 | 
					    mock(resource).authorize_resource
 | 
				
			||||||
 | 
					    resource.load_and_authorize_resource
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it "should not build a resource when on custom collection action" do
 | 
				
			||||||
 | 
					    resource = CanCan::ControllerResource.new(@controller, {:controller => "abilities", :action => "sort"}, {:collection => [:sort, :list]})
 | 
				
			||||||
 | 
					    resource.load_resource
 | 
				
			||||||
 | 
					    @controller.instance_variable_get(:@ability).should be_nil
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it "should build a resource when on custom new action even when params[:id] exists" do
 | 
				
			||||||
 | 
					    stub(Ability).new(nil) { :some_resource }
 | 
				
			||||||
 | 
					    resource = CanCan::ControllerResource.new(@controller, {:controller => "abilities", :action => "build", :id => 123}, {:new => :build})
 | 
				
			||||||
 | 
					    resource.load_resource
 | 
				
			||||||
 | 
					    @controller.instance_variable_get(:@ability).should == :some_resource
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it "should not try to load resource for other action if params[:id] is undefined" do
 | 
				
			||||||
 | 
					    resource = CanCan::ControllerResource.new(@controller, :controller => "abilities", :action => "list")
 | 
				
			||||||
 | 
					    resource.load_resource
 | 
				
			||||||
 | 
					    @controller.instance_variable_get(:@ability).should be_nil
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it "should be a parent resource when name is provided which doesn't match controller" do
 | 
				
			||||||
 | 
					    resource = CanCan::ControllerResource.new(@controller, {:controller => "abilities"}, :person)
 | 
				
			||||||
 | 
					    resource.should be_parent
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it "should not be a parent resource when name is provided which matches controller" do
 | 
				
			||||||
 | 
					    resource = CanCan::ControllerResource.new(@controller, {:controller => "abilities"}, :ability)
 | 
				
			||||||
 | 
					    resource.should_not be_parent
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it "should be parent if specified in options" do
 | 
				
			||||||
 | 
					    resource = CanCan::ControllerResource.new(@controller, {:controller => "abilities"}, :ability, {:parent => true})
 | 
				
			||||||
 | 
					    resource.should be_parent
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it "should load parent resource through proper id parameter when supplying a resource with a different name" do
 | 
				
			||||||
 | 
					    stub(Person).find(123) { :some_person }
 | 
				
			||||||
 | 
					    resource = CanCan::ControllerResource.new(@controller, {:controller => "abilities", :action => "index", :person_id => 123}, :person)
 | 
				
			||||||
 | 
					    resource.load_resource
 | 
				
			||||||
 | 
					    @controller.instance_variable_get(:@person).should == :some_person
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it "should load parent resource for collection action" do
 | 
				
			||||||
 | 
					    stub(Person).find(456) { :some_person }
 | 
				
			||||||
 | 
					    resource = CanCan::ControllerResource.new(@controller, {:controller => "abilities", :action => "index", :person_id => 456}, :person)
 | 
				
			||||||
 | 
					    resource.load_resource
 | 
				
			||||||
 | 
					    @controller.instance_variable_get(:@person).should == :some_person
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it "should load resource through the association of another parent resource" do
 | 
				
			||||||
 | 
					    person = Object.new
 | 
				
			||||||
 | 
					    @controller.instance_variable_set(:@person, person)
 | 
				
			||||||
 | 
					    stub(person).abilities.stub!.find(123) { :some_ability }
 | 
				
			||||||
 | 
					    resource = CanCan::ControllerResource.new(@controller, {:controller => "abilities", :action => "show", :id => 123}, {:through => :person})
 | 
				
			||||||
 | 
					    resource.load_resource
 | 
				
			||||||
 | 
					    @controller.instance_variable_get(:@ability).should == :some_ability
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it "should not load through parent resource if instance isn't loaded" do
 | 
				
			||||||
 | 
					    stub(Ability).find(123) { :some_ability }
 | 
				
			||||||
 | 
					    resource = CanCan::ControllerResource.new(@controller, {:controller => "abilities", :action => "show", :id => 123}, {:through => :person})
 | 
				
			||||||
 | 
					    resource.load_resource
 | 
				
			||||||
 | 
					    @controller.instance_variable_get(:@ability).should == :some_ability
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it "should load the model using a custom class" do
 | 
				
			||||||
 | 
					    stub(Person).find(123) { :some_resource }
 | 
				
			||||||
 | 
					    resource = CanCan::ControllerResource.new(@controller, {:controller => "abilities", :action => "show", :id => 123}, {:class => Person})
 | 
				
			||||||
 | 
					    resource.load_resource
 | 
				
			||||||
 | 
					    @controller.instance_variable_get(:@ability).should == :some_resource
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it "should authorize based on resource name if class is false" do
 | 
				
			||||||
 | 
					    stub(@controller).authorize!(:show, :ability) { raise CanCan::AccessDenied }
 | 
				
			||||||
 | 
					    resource = CanCan::ControllerResource.new(@controller, {:controller => "abilities", :action => "show", :id => 123}, {:class => false})
 | 
				
			||||||
 | 
					    lambda { resource.authorize_resource }.should raise_error(CanCan::AccessDenied)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it "should raise ImplementationRemoved when adding :name option" do
 | 
				
			||||||
    lambda {
 | 
					    lambda {
 | 
				
			||||||
      CanCan::ControllerResource.new(@controller, :ability, nil, :class => Person)
 | 
					      CanCan::ControllerResource.new(@controller, {}, {:name => :foo})
 | 
				
			||||||
 | 
					    }.should raise_error(CanCan::ImplementationRemoved)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it "should raise ImplementationRemoved exception when specifying :resource option since it is no longer used" do
 | 
				
			||||||
 | 
					    lambda {
 | 
				
			||||||
 | 
					      CanCan::ControllerResource.new(@controller, {}, {:resource => Person})
 | 
				
			||||||
 | 
					    }.should raise_error(CanCan::ImplementationRemoved)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it "should raise ImplementationRemoved exception when passing :nested option" do
 | 
				
			||||||
 | 
					    lambda {
 | 
				
			||||||
 | 
					      CanCan::ControllerResource.new(@controller, {}, {:nested => :person})
 | 
				
			||||||
    }.should raise_error(CanCan::ImplementationRemoved)
 | 
					    }.should raise_error(CanCan::ImplementationRemoved)
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
				
			|||||||
@ -1,135 +0,0 @@
 | 
				
			|||||||
require "spec_helper"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
describe CanCan::ResourceAuthorization do
 | 
					 | 
				
			||||||
  before(:each) do
 | 
					 | 
				
			||||||
    @controller = Object.new # simple stub for now
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it "should load the resource into an instance variable if params[:id] is specified" do
 | 
					 | 
				
			||||||
    stub(Ability).find(123) { :some_resource }
 | 
					 | 
				
			||||||
    authorization = CanCan::ResourceAuthorization.new(@controller, :controller => "abilities", :action => "show", :id => 123)
 | 
					 | 
				
			||||||
    authorization.load_resource
 | 
					 | 
				
			||||||
    @controller.instance_variable_get(:@ability).should == :some_resource
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it "should properly load resource for namespaced controller" do
 | 
					 | 
				
			||||||
    stub(Ability).find(123) { :some_resource }
 | 
					 | 
				
			||||||
    authorization = CanCan::ResourceAuthorization.new(@controller, :controller => "admin/abilities", :action => "show", :id => 123)
 | 
					 | 
				
			||||||
    authorization.load_resource
 | 
					 | 
				
			||||||
    @controller.instance_variable_get(:@ability).should == :some_resource
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it "should properly load resource for namespaced controller when using '::' for namespace" do
 | 
					 | 
				
			||||||
    stub(Ability).find(123) { :some_resource }
 | 
					 | 
				
			||||||
    authorization = CanCan::ResourceAuthorization.new(@controller, :controller => "Admin::AbilitiesController", :action => "show", :id => 123)
 | 
					 | 
				
			||||||
    authorization.load_resource
 | 
					 | 
				
			||||||
    @controller.instance_variable_get(:@ability).should == :some_resource
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it "should build a new resource with hash if params[:id] is not specified" do
 | 
					 | 
				
			||||||
    stub(Ability).new(:foo => "bar") { :some_resource }
 | 
					 | 
				
			||||||
    authorization = CanCan::ResourceAuthorization.new(@controller, :controller => "abilities", :action => "create", :ability => {:foo => "bar"})
 | 
					 | 
				
			||||||
    authorization.load_resource
 | 
					 | 
				
			||||||
    @controller.instance_variable_get(:@ability).should == :some_resource
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it "should build a new resource even if attribute hash isn't specified" do
 | 
					 | 
				
			||||||
    stub(Ability).new(nil) { :some_resource }
 | 
					 | 
				
			||||||
    authorization = CanCan::ResourceAuthorization.new(@controller, :controller => "abilities", :action => "new")
 | 
					 | 
				
			||||||
    authorization.load_resource
 | 
					 | 
				
			||||||
    @controller.instance_variable_get(:@ability).should == :some_resource
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it "should not build a resource when on index action" do
 | 
					 | 
				
			||||||
    authorization = CanCan::ResourceAuthorization.new(@controller, :controller => "abilities", :action => "index")
 | 
					 | 
				
			||||||
    authorization.load_resource
 | 
					 | 
				
			||||||
    @controller.instance_variable_get(:@ability).should be_nil
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it "should perform authorization using controller action and loaded model" do
 | 
					 | 
				
			||||||
    @controller.instance_variable_set(:@ability, :some_resource)
 | 
					 | 
				
			||||||
    stub(@controller).authorize!(:show, :some_resource) { raise CanCan::AccessDenied }
 | 
					 | 
				
			||||||
    authorization = CanCan::ResourceAuthorization.new(@controller, :controller => "abilities", :action => "show")
 | 
					 | 
				
			||||||
    lambda { authorization.authorize_resource }.should raise_error(CanCan::AccessDenied)
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it "should perform authorization using controller action and non loaded model" do
 | 
					 | 
				
			||||||
    stub(@controller).authorize!(:show, Ability) { raise CanCan::AccessDenied }
 | 
					 | 
				
			||||||
    authorization = CanCan::ResourceAuthorization.new(@controller, :controller => "abilities", :action => "show")
 | 
					 | 
				
			||||||
    lambda { authorization.authorize_resource }.should raise_error(CanCan::AccessDenied)
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it "should call load_resource and authorize_resource for load_and_authorize_resource" do
 | 
					 | 
				
			||||||
    authorization = CanCan::ResourceAuthorization.new(@controller, :controller => "abilities", :action => "show")
 | 
					 | 
				
			||||||
    mock(authorization).load_resource
 | 
					 | 
				
			||||||
    mock(authorization).authorize_resource
 | 
					 | 
				
			||||||
    authorization.load_and_authorize_resource
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it "should not build a resource when on custom collection action" do
 | 
					 | 
				
			||||||
    authorization = CanCan::ResourceAuthorization.new(@controller, {:controller => "abilities", :action => "sort"}, {:collection => [:sort, :list]})
 | 
					 | 
				
			||||||
    authorization.load_resource
 | 
					 | 
				
			||||||
    @controller.instance_variable_get(:@ability).should be_nil
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it "should build a resource when on custom new action even when params[:id] exists" do
 | 
					 | 
				
			||||||
    stub(Ability).new(nil) { :some_resource }
 | 
					 | 
				
			||||||
    authorization = CanCan::ResourceAuthorization.new(@controller, {:controller => "abilities", :action => "build", :id => 123}, {:new => :build})
 | 
					 | 
				
			||||||
    authorization.load_resource
 | 
					 | 
				
			||||||
    @controller.instance_variable_get(:@ability).should == :some_resource
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it "should not try to load resource for other action if params[:id] is undefined" do
 | 
					 | 
				
			||||||
    authorization = CanCan::ResourceAuthorization.new(@controller, :controller => "abilities", :action => "list")
 | 
					 | 
				
			||||||
    authorization.load_resource
 | 
					 | 
				
			||||||
    @controller.instance_variable_get(:@ability).should be_nil
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it "should load nested resource and fetch other resource through the association" do
 | 
					 | 
				
			||||||
    person = Object.new
 | 
					 | 
				
			||||||
    stub(Person).find(456) { person }
 | 
					 | 
				
			||||||
    stub(person).abilities.stub!.find(123) { :some_ability }
 | 
					 | 
				
			||||||
    authorization = CanCan::ResourceAuthorization.new(@controller, {:controller => "abilities", :action => "show", :id => 123, :person_id => 456}, {:nested => :person})
 | 
					 | 
				
			||||||
    authorization.load_resource
 | 
					 | 
				
			||||||
    @controller.instance_variable_get(:@person).should == person
 | 
					 | 
				
			||||||
    @controller.instance_variable_get(:@ability).should == :some_ability
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it "should load nested resource for collection action" do
 | 
					 | 
				
			||||||
    person = Object.new
 | 
					 | 
				
			||||||
    stub(Person).find(456) { person }
 | 
					 | 
				
			||||||
    authorization = CanCan::ResourceAuthorization.new(@controller, {:controller => "abilities", :action => "index", :person_id => 456}, {:nested => :person})
 | 
					 | 
				
			||||||
    authorization.load_resource
 | 
					 | 
				
			||||||
    @controller.instance_variable_get(:@person).should == person
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it "should load nested resource and build resource through a deep association" do
 | 
					 | 
				
			||||||
    stub(Person).find(456).stub!.behaviors.stub!.find(789).stub!.abilities.stub!.build(nil) { :some_ability }
 | 
					 | 
				
			||||||
    authorization = CanCan::ResourceAuthorization.new(@controller, {:controller => "abilities", :action => "new", :person_id => 456, :behavior_id => 789}, {:nested => [:person, :behavior]})
 | 
					 | 
				
			||||||
    authorization.load_resource
 | 
					 | 
				
			||||||
    @controller.instance_variable_get(:@ability).should == :some_ability
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it "should not load nested resource and build through this if *_id param isn't specified" do
 | 
					 | 
				
			||||||
    stub(Person).find(456) { :some_person }
 | 
					 | 
				
			||||||
    stub(Ability).new(nil) { :some_ability }
 | 
					 | 
				
			||||||
    authorization = CanCan::ResourceAuthorization.new(@controller, {:controller => "abilities", :action => "new", :person_id => 456}, {:nested => [:person, :behavior]})
 | 
					 | 
				
			||||||
    authorization.load_resource
 | 
					 | 
				
			||||||
    @controller.instance_variable_get(:@person).should == :some_person
 | 
					 | 
				
			||||||
    @controller.instance_variable_get(:@ability).should == :some_ability
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it "should load the model using a custom class" do
 | 
					 | 
				
			||||||
    stub(Person).find(123) { :some_resource }
 | 
					 | 
				
			||||||
    authorization = CanCan::ResourceAuthorization.new(@controller, {:controller => "abilities", :action => "show", :id => 123}, {:resource => Person})
 | 
					 | 
				
			||||||
    authorization.load_resource
 | 
					 | 
				
			||||||
    @controller.instance_variable_get(:@ability).should == :some_resource
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it "should use :name option to determine resource name" do
 | 
					 | 
				
			||||||
    stub(Ability).find(123) { :some_resource }
 | 
					 | 
				
			||||||
    authorization = CanCan::ResourceAuthorization.new(@controller, {:controller => "foo", :action => "show", :id => 123}, {:name => :ability})
 | 
					 | 
				
			||||||
    authorization.load_resource
 | 
					 | 
				
			||||||
    @controller.instance_variable_get(:@ability).should == :some_resource
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
end
 | 
					 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user