change how params are passed to ControllerResource and use HashWithIndifferentAccess in tests

This commit is contained in:
Ryan Bates 2010-08-06 09:24:01 -07:00
parent 67b069579e
commit 47f0aa597e
3 changed files with 56 additions and 34 deletions

View File

@ -4,13 +4,13 @@ module CanCan
class ControllerResource # :nodoc: class ControllerResource # :nodoc:
def self.add_before_filter(controller_class, method, options = {}) def self.add_before_filter(controller_class, method, options = {})
controller_class.before_filter(options.slice(:only, :except)) do |controller| controller_class.before_filter(options.slice(:only, :except)) do |controller|
ControllerResource.new(controller, controller.params, options.except(:only, :except)).send(method) ControllerResource.new(controller, options.except(:only, :except)).send(method)
end end
end end
def initialize(controller, params, *args) def initialize(controller, *args)
@controller = controller @controller = controller
@params = params @params = controller.params
@options = args.extract_options! @options = args.extract_options!
@name = args.first @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 :nested option is no longer supported, instead use :through with separate load/authorize call." if @options[:nested]
@ -41,7 +41,7 @@ module CanCan
def load_resource_instance def load_resource_instance
if !parent? && new_actions.include?(@params[:action].to_sym) if !parent? && new_actions.include?(@params[:action].to_sym)
@params[name.to_sym] ? resource_base.new(@params[name.to_sym]) : resource_base.new @params[name] ? resource_base.new(@params[name]) : resource_base.new
elsif id_param elsif id_param
resource_base.find(id_param) resource_base.find(id_param)
end end

View File

@ -53,19 +53,19 @@ describe CanCan::ControllerAdditions do
end end
it "load_and_authorize_resource should setup a before filter which passes call to ControllerResource" do it "load_and_authorize_resource should setup a before filter which passes call to ControllerResource" do
stub(CanCan::ControllerResource).new(@controller, @controller.params, :foo => :bar).mock!.load_and_authorize_resource stub(CanCan::ControllerResource).new(@controller, :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 ControllerResource" do it "authorize_resource should setup a before filter which passes call to ControllerResource" do
stub(CanCan::ControllerResource).new(@controller, @controller.params, :foo => :bar).mock!.authorize_resource stub(CanCan::ControllerResource).new(@controller, :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 ControllerResource" do it "load_resource should setup a before filter which passes call to ControllerResource" do
stub(CanCan::ControllerResource).new(@controller, @controller.params, :foo => :bar).mock!.load_resource stub(CanCan::ControllerResource).new(@controller, :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

View File

@ -2,176 +2,198 @@ require "spec_helper"
describe CanCan::ControllerResource do describe CanCan::ControllerResource do
before(:each) do before(:each) do
@params = HashWithIndifferentAccess.new(:controller => "abilities")
@controller = Object.new # simple stub for now @controller = Object.new # simple stub for now
stub(@controller).params { @params }
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
@params.merge!(:action => "show", :id => 123)
stub(Ability).find(123) { :some_resource } stub(Ability).find(123) { :some_resource }
resource = CanCan::ControllerResource.new(@controller, :controller => "abilities", :action => "show", :id => 123) resource = CanCan::ControllerResource.new(@controller)
resource.load_resource resource.load_resource
@controller.instance_variable_get(:@ability).should == :some_resource @controller.instance_variable_get(:@ability).should == :some_resource
end end
it "should not load resource into an instance variable if already set" do it "should not load resource into an instance variable if already set" do
@params.merge!(:action => "show", :id => 123)
@controller.instance_variable_set(:@ability, :some_ability) @controller.instance_variable_set(:@ability, :some_ability)
resource = CanCan::ControllerResource.new(@controller, :controller => "abilities", :action => "show", :id => 123) resource = CanCan::ControllerResource.new(@controller)
resource.load_resource resource.load_resource
@controller.instance_variable_get(:@ability).should == :some_ability @controller.instance_variable_get(:@ability).should == :some_ability
end end
it "should properly load resource for namespaced controller" do it "should properly load resource for namespaced controller" do
@params.merge!(:controller => "admin/abilities", :action => "show", :id => 123)
stub(Ability).find(123) { :some_resource } stub(Ability).find(123) { :some_resource }
resource = CanCan::ControllerResource.new(@controller, :controller => "admin/abilities", :action => "show", :id => 123) resource = CanCan::ControllerResource.new(@controller)
resource.load_resource resource.load_resource
@controller.instance_variable_get(:@ability).should == :some_resource @controller.instance_variable_get(:@ability).should == :some_resource
end end
it "should properly load resource for namespaced controller when using '::' for namespace" do it "should properly load resource for namespaced controller when using '::' for namespace" do
@params.merge!(:controller => "Admin::AbilitiesController", :action => "show", :id => 123)
stub(Ability).find(123) { :some_resource } stub(Ability).find(123) { :some_resource }
resource = CanCan::ControllerResource.new(@controller, :controller => "Admin::AbilitiesController", :action => "show", :id => 123) resource = CanCan::ControllerResource.new(@controller)
resource.load_resource resource.load_resource
@controller.instance_variable_get(:@ability).should == :some_resource @controller.instance_variable_get(:@ability).should == :some_resource
end end
it "should build a new resource with hash if params[:id] is not specified" do it "should build a new resource with hash if params[:id] is not specified" do
stub(Ability).new(:foo => "bar") { :some_resource } @params.merge!(:action => "create", :ability => {:foo => "bar"})
resource = CanCan::ControllerResource.new(@controller, :controller => "abilities", :action => "create", :ability => {:foo => "bar"}) stub(Ability).new("foo" => "bar") { :some_resource }
resource = CanCan::ControllerResource.new(@controller)
resource.load_resource resource.load_resource
@controller.instance_variable_get(:@ability).should == :some_resource @controller.instance_variable_get(:@ability).should == :some_resource
end end
it "should build a new resource with no arguments if attribute hash isn't specified" do it "should build a new resource with no arguments if attribute hash isn't specified" do
@params[:action] = "new"
mock(Ability).new { :some_resource } mock(Ability).new { :some_resource }
resource = CanCan::ControllerResource.new(@controller, :controller => "abilities", :action => "new") resource = CanCan::ControllerResource.new(@controller)
resource.load_resource resource.load_resource
@controller.instance_variable_get(:@ability).should == :some_resource @controller.instance_variable_get(:@ability).should == :some_resource
end end
it "should not build a resource when on index action" do it "should not build a resource when on index action" do
resource = CanCan::ControllerResource.new(@controller, :controller => "abilities", :action => "index") @params[:action] = "index"
resource = CanCan::ControllerResource.new(@controller)
resource.load_resource resource.load_resource
@controller.instance_variable_get(:@ability).should be_nil @controller.instance_variable_get(:@ability).should be_nil
end end
it "should perform authorization using controller action and loaded model" do it "should perform authorization using controller action and loaded model" do
@params[:action] = "show"
@controller.instance_variable_set(:@ability, :some_resource) @controller.instance_variable_set(:@ability, :some_resource)
stub(@controller).authorize!(:show, :some_resource) { raise CanCan::AccessDenied } stub(@controller).authorize!(:show, :some_resource) { raise CanCan::AccessDenied }
resource = CanCan::ControllerResource.new(@controller, :controller => "abilities", :action => "show") resource = CanCan::ControllerResource.new(@controller)
lambda { resource.authorize_resource }.should raise_error(CanCan::AccessDenied) lambda { resource.authorize_resource }.should raise_error(CanCan::AccessDenied)
end end
it "should perform authorization using controller action and non loaded model" do it "should perform authorization using controller action and non loaded model" do
@params[:action] = "show"
stub(@controller).authorize!(:show, Ability) { raise CanCan::AccessDenied } stub(@controller).authorize!(:show, Ability) { raise CanCan::AccessDenied }
resource = CanCan::ControllerResource.new(@controller, :controller => "abilities", :action => "show") resource = CanCan::ControllerResource.new(@controller)
lambda { resource.authorize_resource }.should raise_error(CanCan::AccessDenied) lambda { resource.authorize_resource }.should raise_error(CanCan::AccessDenied)
end end
it "should call load_resource and authorize_resource for load_and_authorize_resource" do it "should call load_resource and authorize_resource for load_and_authorize_resource" do
resource = CanCan::ControllerResource.new(@controller, :controller => "abilities", :action => "show") @params[:action] = "show"
resource = CanCan::ControllerResource.new(@controller)
mock(resource).load_resource mock(resource).load_resource
mock(resource).authorize_resource mock(resource).authorize_resource
resource.load_and_authorize_resource resource.load_and_authorize_resource
end end
it "should not build a resource when on custom collection action" do it "should not build a resource when on custom collection action" do
resource = CanCan::ControllerResource.new(@controller, {:controller => "abilities", :action => "sort"}, {:collection => [:sort, :list]}) @params[:action] = "sort"
resource = CanCan::ControllerResource.new(@controller, :collection => [:sort, :list])
resource.load_resource resource.load_resource
@controller.instance_variable_get(:@ability).should be_nil @controller.instance_variable_get(:@ability).should be_nil
end end
it "should build a resource when on custom new action even when params[:id] exists" do it "should build a resource when on custom new action even when params[:id] exists" do
@params.merge!(:action => "build", :id => 123)
stub(Ability).new { :some_resource } stub(Ability).new { :some_resource }
resource = CanCan::ControllerResource.new(@controller, {:controller => "abilities", :action => "build", :id => 123}, {:new => :build}) resource = CanCan::ControllerResource.new(@controller, :new => :build)
resource.load_resource resource.load_resource
@controller.instance_variable_get(:@ability).should == :some_resource @controller.instance_variable_get(:@ability).should == :some_resource
end end
it "should not try to load resource for other action if params[:id] is undefined" do 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") @params[:action] = "list"
resource = CanCan::ControllerResource.new(@controller)
resource.load_resource resource.load_resource
@controller.instance_variable_get(:@ability).should be_nil @controller.instance_variable_get(:@ability).should be_nil
end end
it "should be a parent resource when name is provided which doesn't match controller" do 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 = CanCan::ControllerResource.new(@controller, :person)
resource.should be_parent resource.should be_parent
end end
it "should not be a parent resource when name is provided which matches controller" do it "should not be a parent resource when name is provided which matches controller" do
resource = CanCan::ControllerResource.new(@controller, {:controller => "abilities"}, :ability) resource = CanCan::ControllerResource.new(@controller, :ability)
resource.should_not be_parent resource.should_not be_parent
end end
it "should be parent if specified in options" do it "should be parent if specified in options" do
resource = CanCan::ControllerResource.new(@controller, {:controller => "abilities"}, :ability, {:parent => true}) resource = CanCan::ControllerResource.new(@controller, :ability, {:parent => true})
resource.should be_parent resource.should be_parent
end end
it "should load parent resource through proper id parameter when supplying a resource with a different name" do it "should load parent resource through proper id parameter when supplying a resource with a different name" do
@params.merge!(:action => "index", :person_id => 123)
stub(Person).find(123) { :some_person } stub(Person).find(123) { :some_person }
resource = CanCan::ControllerResource.new(@controller, {:controller => "abilities", :action => "index", :person_id => 123}, :person) resource = CanCan::ControllerResource.new(@controller, :person)
resource.load_resource resource.load_resource
@controller.instance_variable_get(:@person).should == :some_person @controller.instance_variable_get(:@person).should == :some_person
end end
it "should load parent resource for collection action" do it "should load parent resource for collection action" do
@params.merge!(:action => "index", :person_id => 456)
stub(Person).find(456) { :some_person } stub(Person).find(456) { :some_person }
resource = CanCan::ControllerResource.new(@controller, {:controller => "abilities", :action => "index", :person_id => 456}, :person) resource = CanCan::ControllerResource.new(@controller, :person)
resource.load_resource resource.load_resource
@controller.instance_variable_get(:@person).should == :some_person @controller.instance_variable_get(:@person).should == :some_person
end end
it "should load resource through the association of another parent resource" do it "should load resource through the association of another parent resource" do
@params.merge!(:action => "show", :id => 123)
person = Object.new person = Object.new
@controller.instance_variable_set(:@person, person) @controller.instance_variable_set(:@person, person)
stub(person).abilities.stub!.find(123) { :some_ability } stub(person).abilities.stub!.find(123) { :some_ability }
resource = CanCan::ControllerResource.new(@controller, {:controller => "abilities", :action => "show", :id => 123}, {:through => :person}) resource = CanCan::ControllerResource.new(@controller, :through => :person)
resource.load_resource resource.load_resource
@controller.instance_variable_get(:@ability).should == :some_ability @controller.instance_variable_get(:@ability).should == :some_ability
end end
it "should not load through parent resource if instance isn't loaded" do it "should not load through parent resource if instance isn't loaded" do
@params.merge!(:action => "show", :id => 123)
stub(Ability).find(123) { :some_ability } stub(Ability).find(123) { :some_ability }
resource = CanCan::ControllerResource.new(@controller, {:controller => "abilities", :action => "show", :id => 123}, {:through => :person}) resource = CanCan::ControllerResource.new(@controller, :through => :person)
resource.load_resource resource.load_resource
@controller.instance_variable_get(:@ability).should == :some_ability @controller.instance_variable_get(:@ability).should == :some_ability
end end
it "should only authorize :read action on parent resource" do it "should only authorize :read action on parent resource" do
@params.merge!(:action => "new", :person_id => 123)
stub(Person).find(123) { :some_person } stub(Person).find(123) { :some_person }
stub(@controller).authorize!(:read, :some_person) { raise CanCan::AccessDenied } stub(@controller).authorize!(:read, :some_person) { raise CanCan::AccessDenied }
resource = CanCan::ControllerResource.new(@controller, {:controller => "abilities", :action => "new", :person_id => 123}, :person) resource = CanCan::ControllerResource.new(@controller, :person)
lambda { resource.load_and_authorize_resource }.should raise_error(CanCan::AccessDenied) lambda { resource.load_and_authorize_resource }.should raise_error(CanCan::AccessDenied)
end end
it "should load the model using a custom class" do it "should load the model using a custom class" do
@params.merge!(:action => "show", :id => 123)
stub(Person).find(123) { :some_resource } stub(Person).find(123) { :some_resource }
resource = CanCan::ControllerResource.new(@controller, {:controller => "abilities", :action => "show", :id => 123}, {:class => Person}) resource = CanCan::ControllerResource.new(@controller, :class => Person)
resource.load_resource resource.load_resource
@controller.instance_variable_get(:@ability).should == :some_resource @controller.instance_variable_get(:@ability).should == :some_resource
end end
it "should authorize based on resource name if class is false" do it "should authorize based on resource name if class is false" do
@params.merge!(:action => "show", :id => 123)
stub(@controller).authorize!(:show, :ability) { raise CanCan::AccessDenied } stub(@controller).authorize!(:show, :ability) { raise CanCan::AccessDenied }
resource = CanCan::ControllerResource.new(@controller, {:controller => "abilities", :action => "show", :id => 123}, {:class => false}) resource = CanCan::ControllerResource.new(@controller, :class => false)
lambda { resource.authorize_resource }.should raise_error(CanCan::AccessDenied) lambda { resource.authorize_resource }.should raise_error(CanCan::AccessDenied)
end end
it "should raise ImplementationRemoved when adding :name option" do it "should raise ImplementationRemoved when adding :name option" do
lambda { lambda {
CanCan::ControllerResource.new(@controller, {}, {:name => :foo}) CanCan::ControllerResource.new(@controller, :name => :foo)
}.should raise_error(CanCan::ImplementationRemoved) }.should raise_error(CanCan::ImplementationRemoved)
end end
it "should raise ImplementationRemoved exception when specifying :resource option since it is no longer used" do it "should raise ImplementationRemoved exception when specifying :resource option since it is no longer used" do
lambda { lambda {
CanCan::ControllerResource.new(@controller, {}, {:resource => Person}) CanCan::ControllerResource.new(@controller, :resource => Person)
}.should raise_error(CanCan::ImplementationRemoved) }.should raise_error(CanCan::ImplementationRemoved)
end end
it "should raise ImplementationRemoved exception when passing :nested option" do it "should raise ImplementationRemoved exception when passing :nested option" do
lambda { lambda {
CanCan::ControllerResource.new(@controller, {}, {:nested => :person}) CanCan::ControllerResource.new(@controller, :nested => :person)
}.should raise_error(CanCan::ImplementationRemoved) }.should raise_error(CanCan::ImplementationRemoved)
end end
end end