adding skip load and authorize behavior - closes #164
This commit is contained in:
		
							parent
							
								
									71ceb83ded
								
							
						
					
					
						commit
						57327119a8
					
				@ -166,6 +166,52 @@ module CanCan
 | 
				
			|||||||
        cancan_resource_class.add_before_filter(self, :authorize_resource, *args)
 | 
					        cancan_resource_class.add_before_filter(self, :authorize_resource, *args)
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      # Skip both the loading and authorization behavior of CanCan for this given controller. This is primarily
 | 
				
			||||||
 | 
					      # useful to skip the behavior of a superclass. You can pass :only and :except options to specify which actions
 | 
				
			||||||
 | 
					      # to skip the effects on. It will apply to all actions by default.
 | 
				
			||||||
 | 
					      #
 | 
				
			||||||
 | 
					      #   class ProjectsController < SomeOtherController
 | 
				
			||||||
 | 
					      #     skip_load_and_authorize_resource :only => :index
 | 
				
			||||||
 | 
					      #   end
 | 
				
			||||||
 | 
					      #
 | 
				
			||||||
 | 
					      # You can also pass the resource name as the first argument to skip that resource.
 | 
				
			||||||
 | 
					      def skip_load_and_authorize_resource(*args)
 | 
				
			||||||
 | 
					        skip_load_resource(*args)
 | 
				
			||||||
 | 
					        skip_authorize_resource(*args)
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      # Skip both the loading behavior of CanCan. This is useful when using +load_and_authorize_resource+ but want to
 | 
				
			||||||
 | 
					      # only do authorization on certain actions. You can pass :only and :except options to specify which actions to
 | 
				
			||||||
 | 
					      # skip the effects on. It will apply to all actions by default.
 | 
				
			||||||
 | 
					      #
 | 
				
			||||||
 | 
					      #   class ProjectsController < ApplicationController
 | 
				
			||||||
 | 
					      #     load_and_authorize_resource
 | 
				
			||||||
 | 
					      #     skip_load_resource :only => :index
 | 
				
			||||||
 | 
					      #   end
 | 
				
			||||||
 | 
					      #
 | 
				
			||||||
 | 
					      # You can also pass the resource name as the first argument to skip that resource.
 | 
				
			||||||
 | 
					      def skip_load_resource(*args)
 | 
				
			||||||
 | 
					        options = args.extract_options!
 | 
				
			||||||
 | 
					        name = args.first
 | 
				
			||||||
 | 
					        cancan_skipper[:load][name] = options
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      # Skip both the authorization behavior of CanCan. This is useful when using +load_and_authorize_resource+ but want to
 | 
				
			||||||
 | 
					      # only do loading on certain actions. You can pass :only and :except options to specify which actions to
 | 
				
			||||||
 | 
					      # skip the effects on. It will apply to all actions by default.
 | 
				
			||||||
 | 
					      #
 | 
				
			||||||
 | 
					      #   class ProjectsController < ApplicationController
 | 
				
			||||||
 | 
					      #     load_and_authorize_resource
 | 
				
			||||||
 | 
					      #     skip_authorize_resource :only => :index
 | 
				
			||||||
 | 
					      #   end
 | 
				
			||||||
 | 
					      #
 | 
				
			||||||
 | 
					      # You can also pass the resource name as the first argument to skip that resource.
 | 
				
			||||||
 | 
					      def skip_authorize_resource(*args)
 | 
				
			||||||
 | 
					        options = args.extract_options!
 | 
				
			||||||
 | 
					        name = args.first
 | 
				
			||||||
 | 
					        cancan_skipper[:authorize][name] = options
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      # Add this to a controller to ensure it performs authorization through +authorized+! or +authorize_resource+ call.
 | 
					      # Add this to a controller to ensure it performs authorization through +authorized+! or +authorize_resource+ call.
 | 
				
			||||||
      # If neither of these authorization methods are called, a CanCan::AuthorizationNotPerformed exception will be raised.
 | 
					      # If neither of these authorization methods are called, a CanCan::AuthorizationNotPerformed exception will be raised.
 | 
				
			||||||
      # This is normally added to the ApplicationController to ensure all controller actions do authorization.
 | 
					      # This is normally added to the ApplicationController to ensure all controller actions do authorization.
 | 
				
			||||||
@ -209,6 +255,10 @@ module CanCan
 | 
				
			|||||||
          ControllerResource
 | 
					          ControllerResource
 | 
				
			||||||
        end
 | 
					        end
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      def cancan_skipper
 | 
				
			||||||
 | 
					        @_cancan_skipper ||= {:authorize => {}, :load => {}}
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def self.included(base)
 | 
					    def self.included(base)
 | 
				
			||||||
 | 
				
			|||||||
@ -26,21 +26,38 @@ module CanCan
 | 
				
			|||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def load_resource
 | 
					    def load_resource
 | 
				
			||||||
 | 
					      unless skip?(:load)
 | 
				
			||||||
        if load_instance?
 | 
					        if load_instance?
 | 
				
			||||||
          self.resource_instance ||= load_resource_instance
 | 
					          self.resource_instance ||= load_resource_instance
 | 
				
			||||||
        elsif load_collection?
 | 
					        elsif load_collection?
 | 
				
			||||||
          self.collection_instance ||= load_collection
 | 
					          self.collection_instance ||= load_collection
 | 
				
			||||||
        end
 | 
					        end
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def authorize_resource
 | 
					    def authorize_resource
 | 
				
			||||||
 | 
					      unless skip?(:authorize)
 | 
				
			||||||
        @controller.authorize!(authorization_action, resource_instance || resource_class_with_parent)
 | 
					        @controller.authorize!(authorization_action, resource_instance || resource_class_with_parent)
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def parent?
 | 
					    def parent?
 | 
				
			||||||
      @options.has_key?(:parent) ? @options[:parent] : @name && @name != name_from_controller.to_sym
 | 
					      @options.has_key?(:parent) ? @options[:parent] : @name && @name != name_from_controller.to_sym
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def skip?(behavior) # This could probably use some refactoring
 | 
				
			||||||
 | 
					      options = @controller.class.cancan_skipper[behavior][@name]
 | 
				
			||||||
 | 
					      if options.nil?
 | 
				
			||||||
 | 
					        false
 | 
				
			||||||
 | 
					      elsif options == {}
 | 
				
			||||||
 | 
					        true
 | 
				
			||||||
 | 
					      elsif options[:except] && ![options[:except]].flatten.include?(@params[:action].to_sym)
 | 
				
			||||||
 | 
					        true
 | 
				
			||||||
 | 
					      elsif [options[:only]].flatten.include?(@params[:action].to_sym)
 | 
				
			||||||
 | 
					        true
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    protected
 | 
					    protected
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def load_resource_instance
 | 
					    def load_resource_instance
 | 
				
			||||||
 | 
				
			|||||||
@ -83,4 +83,34 @@ describe CanCan::ControllerAdditions do
 | 
				
			|||||||
    stub(@controller.class).ancestors { ["InheritedResources::Actions"] }
 | 
					    stub(@controller.class).ancestors { ["InheritedResources::Actions"] }
 | 
				
			||||||
    @controller.class.cancan_resource_class.should == CanCan::InheritedResource
 | 
					    @controller.class.cancan_resource_class.should == CanCan::InheritedResource
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it "cancan_skipper should be an empty hash with :authorize and :load options and remember changes" do
 | 
				
			||||||
 | 
					    @controller_class.cancan_skipper.should == {:authorize => {}, :load => {}}
 | 
				
			||||||
 | 
					    @controller_class.cancan_skipper[:load] = true
 | 
				
			||||||
 | 
					    @controller_class.cancan_skipper[:load].should == true
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it "skip_authorize_resource should add itself to the cancan skipper with given model name and options" do
 | 
				
			||||||
 | 
					    @controller_class.skip_authorize_resource(:project, :only => [:index, :show])
 | 
				
			||||||
 | 
					    @controller_class.cancan_skipper[:authorize][:project].should == {:only => [:index, :show]}
 | 
				
			||||||
 | 
					    @controller_class.skip_authorize_resource(:only => [:index, :show])
 | 
				
			||||||
 | 
					    @controller_class.cancan_skipper[:authorize][nil].should == {:only => [:index, :show]}
 | 
				
			||||||
 | 
					    @controller_class.skip_authorize_resource(:article)
 | 
				
			||||||
 | 
					    @controller_class.cancan_skipper[:authorize][:article].should == {}
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it "skip_load_resource should add itself to the cancan skipper with given model name and options" do
 | 
				
			||||||
 | 
					    @controller_class.skip_load_resource(:project, :only => [:index, :show])
 | 
				
			||||||
 | 
					    @controller_class.cancan_skipper[:load][:project].should == {:only => [:index, :show]}
 | 
				
			||||||
 | 
					    @controller_class.skip_load_resource(:only => [:index, :show])
 | 
				
			||||||
 | 
					    @controller_class.cancan_skipper[:load][nil].should == {:only => [:index, :show]}
 | 
				
			||||||
 | 
					    @controller_class.skip_load_resource(:article)
 | 
				
			||||||
 | 
					    @controller_class.cancan_skipper[:load][:article].should == {}
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it "skip_load_and_authore_resource should add itself to the cancan skipper with given model name and options" do
 | 
				
			||||||
 | 
					    @controller_class.skip_load_and_authorize_resource(:project, :only => [:index, :show])
 | 
				
			||||||
 | 
					    @controller_class.cancan_skipper[:load][:project].should == {:only => [:index, :show]}
 | 
				
			||||||
 | 
					    @controller_class.cancan_skipper[:authorize][:project].should == {:only => [:index, :show]}
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
				
			|||||||
@ -3,10 +3,12 @@ require "spec_helper"
 | 
				
			|||||||
describe CanCan::ControllerResource do
 | 
					describe CanCan::ControllerResource do
 | 
				
			||||||
  before(:each) do
 | 
					  before(:each) do
 | 
				
			||||||
    @params = HashWithIndifferentAccess.new(:controller => "projects")
 | 
					    @params = HashWithIndifferentAccess.new(:controller => "projects")
 | 
				
			||||||
    @controller = Object.new # simple stub for now
 | 
					    @controller_class = Class.new
 | 
				
			||||||
 | 
					    @controller = @controller_class.new
 | 
				
			||||||
    @ability = Ability.new(nil)
 | 
					    @ability = Ability.new(nil)
 | 
				
			||||||
    stub(@controller).params { @params }
 | 
					    stub(@controller).params { @params }
 | 
				
			||||||
    stub(@controller).current_ability { @ability }
 | 
					    stub(@controller).current_ability { @ability }
 | 
				
			||||||
 | 
					    stub(@controller_class).cancan_skipper { {:authorize => {}, :load => {}} }
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  it "should load the resource into an instance variable if params[:id] is specified" do
 | 
					  it "should load the resource into an instance variable if params[:id] is specified" do
 | 
				
			||||||
@ -339,4 +341,52 @@ describe CanCan::ControllerResource do
 | 
				
			|||||||
      CanCan::ControllerResource.new(@controller, :nested => :project)
 | 
					      CanCan::ControllerResource.new(@controller, :nested => :project)
 | 
				
			||||||
    }.should raise_error(CanCan::ImplementationRemoved)
 | 
					    }.should raise_error(CanCan::ImplementationRemoved)
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it "should skip resource behavior for :only actions in array" do
 | 
				
			||||||
 | 
					    stub(@controller_class).cancan_skipper { {:load => {nil => {:only => [:index, :show]}}} }
 | 
				
			||||||
 | 
					    @params.merge!(:action => "index")
 | 
				
			||||||
 | 
					    CanCan::ControllerResource.new(@controller).skip?(:load).should be_true
 | 
				
			||||||
 | 
					    CanCan::ControllerResource.new(@controller, :some_resource).skip?(:load).should be_false
 | 
				
			||||||
 | 
					    @params.merge!(:action => "show")
 | 
				
			||||||
 | 
					    CanCan::ControllerResource.new(@controller).skip?(:load).should be_true
 | 
				
			||||||
 | 
					    @params.merge!(:action => "other_action")
 | 
				
			||||||
 | 
					    CanCan::ControllerResource.new(@controller).skip?(:load).should be_false
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it "should skip resource behavior for :only one action on resource" do
 | 
				
			||||||
 | 
					    stub(@controller_class).cancan_skipper { {:authorize => {:project => {:only => :index}}} }
 | 
				
			||||||
 | 
					    @params.merge!(:action => "index")
 | 
				
			||||||
 | 
					    CanCan::ControllerResource.new(@controller).skip?(:authorize).should be_false
 | 
				
			||||||
 | 
					    CanCan::ControllerResource.new(@controller, :project).skip?(:authorize).should be_true
 | 
				
			||||||
 | 
					    @params.merge!(:action => "other_action")
 | 
				
			||||||
 | 
					    CanCan::ControllerResource.new(@controller, :project).skip?(:authorize).should be_false
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it "should skip resource behavior :except actions in array" do
 | 
				
			||||||
 | 
					    stub(@controller_class).cancan_skipper { {:load => {nil => {:except => [:index, :show]}}} }
 | 
				
			||||||
 | 
					    @params.merge!(:action => "index")
 | 
				
			||||||
 | 
					    CanCan::ControllerResource.new(@controller).skip?(:load).should be_false
 | 
				
			||||||
 | 
					    @params.merge!(:action => "show")
 | 
				
			||||||
 | 
					    CanCan::ControllerResource.new(@controller).skip?(:load).should be_false
 | 
				
			||||||
 | 
					    @params.merge!(:action => "other_action")
 | 
				
			||||||
 | 
					    CanCan::ControllerResource.new(@controller).skip?(:load).should be_true
 | 
				
			||||||
 | 
					    CanCan::ControllerResource.new(@controller, :some_resource).skip?(:load).should be_false
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it "should skip resource behavior :except one action on resource" do
 | 
				
			||||||
 | 
					    stub(@controller_class).cancan_skipper { {:authorize => {:project => {:except => :index}}} }
 | 
				
			||||||
 | 
					    @params.merge!(:action => "index")
 | 
				
			||||||
 | 
					    CanCan::ControllerResource.new(@controller, :project).skip?(:authorize).should be_false
 | 
				
			||||||
 | 
					    @params.merge!(:action => "other_action")
 | 
				
			||||||
 | 
					    CanCan::ControllerResource.new(@controller).skip?(:authorize).should be_false
 | 
				
			||||||
 | 
					    CanCan::ControllerResource.new(@controller, :project).skip?(:authorize).should be_true
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it "should skip loading and authorization" do
 | 
				
			||||||
 | 
					    stub(@controller_class).cancan_skipper { {:authorize => {nil => {}}, :load => {nil => {}}} }
 | 
				
			||||||
 | 
					    @params.merge!(:action => "new")
 | 
				
			||||||
 | 
					    resource = CanCan::ControllerResource.new(@controller)
 | 
				
			||||||
 | 
					    lambda { resource.load_and_authorize_resource }.should_not raise_error
 | 
				
			||||||
 | 
					    @controller.instance_variable_get(:@project).should be_nil
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
				
			|||||||
@ -3,10 +3,12 @@ require "spec_helper"
 | 
				
			|||||||
describe CanCan::InheritedResource do
 | 
					describe CanCan::InheritedResource do
 | 
				
			||||||
  before(:each) do
 | 
					  before(:each) do
 | 
				
			||||||
    @params = HashWithIndifferentAccess.new(:controller => "projects")
 | 
					    @params = HashWithIndifferentAccess.new(:controller => "projects")
 | 
				
			||||||
    @controller = Object.new # simple stub for now
 | 
					    @controller_class = Class.new
 | 
				
			||||||
 | 
					    @controller = @controller_class.new
 | 
				
			||||||
    @ability = Ability.new(nil)
 | 
					    @ability = Ability.new(nil)
 | 
				
			||||||
    stub(@controller).params { @params }
 | 
					    stub(@controller).params { @params }
 | 
				
			||||||
    stub(@controller).current_ability { @ability }
 | 
					    stub(@controller).current_ability { @ability }
 | 
				
			||||||
 | 
					    stub(@controller_class).cancan_skipper { {:authorize => {}, :load => {}} }
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  it "show should load resource through @controller.resource" do
 | 
					  it "show should load resource through @controller.resource" do
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user