402 lines
18 KiB
Ruby
402 lines
18 KiB
Ruby
require "spec_helper"
|
|
|
|
describe CanCan::ControllerResource do
|
|
before(:each) do
|
|
@params = HashWithIndifferentAccess.new(:controller => "projects")
|
|
@controller_class = Class.new
|
|
@controller = @controller_class.new
|
|
@ability = Ability.new(nil)
|
|
stub(@controller).params { @params }
|
|
stub(@controller).current_ability { @ability }
|
|
stub(@controller_class).cancan_skipper { {:authorize => {}, :load => {}} }
|
|
end
|
|
|
|
it "should load the resource into an instance variable if params[:id] is specified" do
|
|
project = Project.create!
|
|
@params.merge!(:action => "show", :id => project.id)
|
|
resource = CanCan::ControllerResource.new(@controller)
|
|
resource.load_resource
|
|
@controller.instance_variable_get(:@project).should == project
|
|
end
|
|
|
|
it "should not load resource into an instance variable if already set" do
|
|
@params.merge!(:action => "show", :id => 123)
|
|
@controller.instance_variable_set(:@project, :some_project)
|
|
resource = CanCan::ControllerResource.new(@controller)
|
|
resource.load_resource
|
|
@controller.instance_variable_get(:@project).should == :some_project
|
|
end
|
|
|
|
it "should properly load resource for namespaced controller" do
|
|
project = Project.create!
|
|
@params.merge!(:controller => "admin/projects", :action => "show", :id => project.id)
|
|
resource = CanCan::ControllerResource.new(@controller)
|
|
resource.load_resource
|
|
@controller.instance_variable_get(:@project).should == project
|
|
end
|
|
|
|
it "should properly load resource for namespaced controller when using '::' for namespace" do
|
|
project = Project.create!
|
|
@params.merge!(:controller => "Admin::ProjectsController", :action => "show", :id => project.id)
|
|
resource = CanCan::ControllerResource.new(@controller)
|
|
resource.load_resource
|
|
@controller.instance_variable_get(:@project).should == project
|
|
end
|
|
|
|
it "should build a new resource with hash if params[:id] is not specified" do
|
|
@params.merge!(:action => "create", :project => {:name => "foobar"})
|
|
resource = CanCan::ControllerResource.new(@controller)
|
|
resource.load_resource
|
|
@controller.instance_variable_get(:@project).name.should == "foobar"
|
|
end
|
|
|
|
it "should build a new resource with attributes from current ability" do
|
|
@params.merge!(:action => "new")
|
|
@ability.can(:create, Project, :name => "from conditions")
|
|
resource = CanCan::ControllerResource.new(@controller)
|
|
resource.load_resource
|
|
@controller.instance_variable_get(:@project).name.should == "from conditions"
|
|
end
|
|
|
|
it "should override initial attributes with params" do
|
|
@params.merge!(:action => "new", :project => {:name => "from params"})
|
|
@ability.can(:create, Project, :name => "from conditions")
|
|
resource = CanCan::ControllerResource.new(@controller)
|
|
resource.load_resource
|
|
@controller.instance_variable_get(:@project).name.should == "from params"
|
|
end
|
|
|
|
it "should build a collection when on index action when class responds to accessible_by" do
|
|
stub(Project).accessible_by(@ability, :index) { :found_projects }
|
|
@params[:action] = "index"
|
|
resource = CanCan::ControllerResource.new(@controller, :project)
|
|
resource.load_resource
|
|
@controller.instance_variable_get(:@project).should be_nil
|
|
@controller.instance_variable_get(:@projects).should == :found_projects
|
|
end
|
|
|
|
it "should not build a collection when on index action when class does not respond to accessible_by" do
|
|
@params[:action] = "index"
|
|
resource = CanCan::ControllerResource.new(@controller)
|
|
resource.load_resource
|
|
@controller.instance_variable_get(:@project).should be_nil
|
|
@controller.instance_variable_defined?(:@projects).should be_false
|
|
end
|
|
|
|
it "should not use accessible_by when defining abilities through a block" do
|
|
stub(Project).accessible_by(@ability) { :found_projects }
|
|
@params[:action] = "index"
|
|
@ability.can(:read, Project) { |p| false }
|
|
resource = CanCan::ControllerResource.new(@controller)
|
|
resource.load_resource
|
|
@controller.instance_variable_get(:@project).should be_nil
|
|
@controller.instance_variable_defined?(:@projects).should be_false
|
|
end
|
|
|
|
it "should not authorize single resource in collection action" do
|
|
@params[:action] = "index"
|
|
@controller.instance_variable_set(:@project, :some_project)
|
|
stub(@controller).authorize!(:index, Project) { raise CanCan::AccessDenied }
|
|
resource = CanCan::ControllerResource.new(@controller)
|
|
lambda { resource.authorize_resource }.should raise_error(CanCan::AccessDenied)
|
|
end
|
|
|
|
it "should authorize parent resource in collection action" do
|
|
@params[:action] = "index"
|
|
@controller.instance_variable_set(:@category, :some_category)
|
|
stub(@controller).authorize!(:read, :some_category) { raise CanCan::AccessDenied }
|
|
resource = CanCan::ControllerResource.new(@controller, :category, :parent => true)
|
|
lambda { resource.authorize_resource }.should raise_error(CanCan::AccessDenied)
|
|
end
|
|
|
|
it "should perform authorization using controller action and loaded model" do
|
|
@params.merge!(:action => "show", :id => 123)
|
|
@controller.instance_variable_set(:@project, :some_project)
|
|
stub(@controller).authorize!(:show, :some_project) { raise CanCan::AccessDenied }
|
|
resource = CanCan::ControllerResource.new(@controller)
|
|
lambda { resource.authorize_resource }.should raise_error(CanCan::AccessDenied)
|
|
end
|
|
|
|
it "should perform authorization using controller action and non loaded model" do
|
|
@params.merge!(:action => "show", :id => 123)
|
|
stub(@controller).authorize!(:show, Project) { raise CanCan::AccessDenied }
|
|
resource = CanCan::ControllerResource.new(@controller)
|
|
lambda { resource.authorize_resource }.should raise_error(CanCan::AccessDenied)
|
|
end
|
|
|
|
it "should call load_resource and authorize_resource for load_and_authorize_resource" do
|
|
@params.merge!(:action => "show", :id => 123)
|
|
resource = CanCan::ControllerResource.new(@controller)
|
|
mock(resource).load_resource
|
|
mock(resource).authorize_resource
|
|
resource.load_and_authorize_resource
|
|
end
|
|
|
|
it "should not build a single resource when on custom collection action even with id" do
|
|
@params.merge!(:action => "sort", :id => 123)
|
|
resource = CanCan::ControllerResource.new(@controller, :collection => [:sort, :list])
|
|
resource.load_resource
|
|
@controller.instance_variable_get(:@project).should be_nil
|
|
end
|
|
|
|
it "should load a collection resource when on custom action with no id param" do
|
|
stub(Project).accessible_by(@ability, :sort) { :found_projects }
|
|
@params[:action] = "sort"
|
|
resource = CanCan::ControllerResource.new(@controller)
|
|
resource.load_resource
|
|
@controller.instance_variable_get(:@project).should be_nil
|
|
@controller.instance_variable_get(:@projects).should == :found_projects
|
|
end
|
|
|
|
it "should build a resource when on custom new action even when params[:id] exists" do
|
|
@params.merge!(:action => "build", :id => 123)
|
|
stub(Project).new { :some_project }
|
|
resource = CanCan::ControllerResource.new(@controller, :new => :build)
|
|
resource.load_resource
|
|
@controller.instance_variable_get(:@project).should == :some_project
|
|
end
|
|
|
|
it "should not try to load resource for other action if params[:id] is undefined" do
|
|
@params[:action] = "list"
|
|
resource = CanCan::ControllerResource.new(@controller)
|
|
resource.load_resource
|
|
@controller.instance_variable_get(:@project).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, :category)
|
|
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, :project)
|
|
resource.should_not be_parent
|
|
end
|
|
|
|
it "should be parent if specified in options" do
|
|
resource = CanCan::ControllerResource.new(@controller, :project, {:parent => true})
|
|
resource.should be_parent
|
|
end
|
|
|
|
it "should not be parent if specified in options" do
|
|
resource = CanCan::ControllerResource.new(@controller, :category, {:parent => false})
|
|
resource.should_not be_parent
|
|
end
|
|
|
|
it "should load parent resource through proper id parameter" do
|
|
project = Project.create!
|
|
@params.merge!(:action => "index", :project_id => project.id)
|
|
resource = CanCan::ControllerResource.new(@controller, :project, :parent => true)
|
|
resource.load_resource
|
|
@controller.instance_variable_get(:@project).should == project
|
|
end
|
|
|
|
it "should load resource through the association of another parent resource using instance variable" do
|
|
@params.merge!(:action => "show", :id => 123)
|
|
category = Object.new
|
|
@controller.instance_variable_set(:@category, category)
|
|
stub(category).projects.stub!.find(123) { :some_project }
|
|
resource = CanCan::ControllerResource.new(@controller, :through => :category)
|
|
resource.load_resource
|
|
@controller.instance_variable_get(:@project).should == :some_project
|
|
end
|
|
|
|
it "should load resource through the custom association name" do
|
|
@params.merge!(:action => "show", :id => 123)
|
|
category = Object.new
|
|
@controller.instance_variable_set(:@category, category)
|
|
stub(category).custom_projects.stub!.find(123) { :some_project }
|
|
resource = CanCan::ControllerResource.new(@controller, :through => :category, :through_association => :custom_projects)
|
|
resource.load_resource
|
|
@controller.instance_variable_get(:@project).should == :some_project
|
|
end
|
|
|
|
it "should load resource through the association of another parent resource using method" do
|
|
@params.merge!(:action => "show", :id => 123)
|
|
category = Object.new
|
|
stub(@controller).category { category }
|
|
stub(category).projects.stub!.find(123) { :some_project }
|
|
resource = CanCan::ControllerResource.new(@controller, :through => :category)
|
|
resource.load_resource
|
|
@controller.instance_variable_get(:@project).should == :some_project
|
|
end
|
|
|
|
it "should not load through parent resource if instance isn't loaded when shallow" do
|
|
project = Project.create!
|
|
@params.merge!(:action => "show", :id => project.id)
|
|
resource = CanCan::ControllerResource.new(@controller, :through => :category, :shallow => true)
|
|
resource.load_resource
|
|
@controller.instance_variable_get(:@project).should == project
|
|
end
|
|
|
|
it "should raise AccessDenied when attempting to load resource through nil" do
|
|
project = Project.create!
|
|
@params.merge!(:action => "show", :id => project.id)
|
|
resource = CanCan::ControllerResource.new(@controller, :through => :category)
|
|
lambda {
|
|
resource.load_resource
|
|
}.should raise_error(CanCan::AccessDenied)
|
|
@controller.instance_variable_get(:@project).should be_nil
|
|
end
|
|
|
|
it "should authorize nested resource through parent association on index action" do
|
|
@params.merge!(:action => "index")
|
|
category = Object.new
|
|
@controller.instance_variable_set(:@category, category)
|
|
stub(@controller).authorize!(:index, category => Project) { raise CanCan::AccessDenied }
|
|
resource = CanCan::ControllerResource.new(@controller, :through => :category)
|
|
lambda { resource.authorize_resource }.should raise_error(CanCan::AccessDenied)
|
|
end
|
|
|
|
it "should load through first matching if multiple are given" do
|
|
@params.merge!(:action => "show", :id => 123)
|
|
category = Object.new
|
|
@controller.instance_variable_set(:@category, category)
|
|
stub(category).projects.stub!.find(123) { :some_project }
|
|
resource = CanCan::ControllerResource.new(@controller, :through => [:category, :user])
|
|
resource.load_resource
|
|
@controller.instance_variable_get(:@project).should == :some_project
|
|
end
|
|
|
|
it "should find record through has_one association with :singleton option" do
|
|
@params.merge!(:action => "show", :id => 123)
|
|
category = Object.new
|
|
@controller.instance_variable_set(:@category, category)
|
|
stub(category).project { :some_project }
|
|
resource = CanCan::ControllerResource.new(@controller, :through => :category, :singleton => true)
|
|
resource.load_resource
|
|
@controller.instance_variable_get(:@project).should == :some_project
|
|
end
|
|
|
|
it "should build record through has_one association with :singleton option" do
|
|
@params.merge!(:action => "create", :project => {:name => "foobar"})
|
|
category = Object.new
|
|
@controller.instance_variable_set(:@category, category)
|
|
stub(category).build_project { |attributes| Project.new(attributes) }
|
|
resource = CanCan::ControllerResource.new(@controller, :through => :category, :singleton => true)
|
|
resource.load_resource
|
|
@controller.instance_variable_get(:@project).name.should == "foobar"
|
|
end
|
|
|
|
it "should find record through has_one association with :singleton and :shallow options" do
|
|
project = Project.create!
|
|
@params.merge!(:action => "show", :id => project.id)
|
|
resource = CanCan::ControllerResource.new(@controller, :through => :category, :singleton => true, :shallow => true)
|
|
resource.load_resource
|
|
@controller.instance_variable_get(:@project).should == project
|
|
end
|
|
|
|
it "should build record through has_one association with :singleton and :shallow options" do
|
|
@params.merge!(:action => "create", :project => {:name => "foobar"})
|
|
resource = CanCan::ControllerResource.new(@controller, :through => :category, :singleton => true, :shallow => true)
|
|
resource.load_resource
|
|
@controller.instance_variable_get(:@project).name.should == "foobar"
|
|
end
|
|
|
|
it "should only authorize :read action on parent resource" do
|
|
project = Project.create!
|
|
@params.merge!(:action => "new", :project_id => project.id)
|
|
stub(@controller).authorize!(:read, project) { raise CanCan::AccessDenied }
|
|
resource = CanCan::ControllerResource.new(@controller, :project, :parent => true)
|
|
lambda { resource.load_and_authorize_resource }.should raise_error(CanCan::AccessDenied)
|
|
end
|
|
|
|
it "should load the model using a custom class" do
|
|
project = Project.create!
|
|
@params.merge!(:action => "show", :id => project.id)
|
|
resource = CanCan::ControllerResource.new(@controller, :class => Project)
|
|
resource.load_resource
|
|
@controller.instance_variable_get(:@project).should == project
|
|
end
|
|
|
|
it "should authorize based on resource name if class is false" do
|
|
@params.merge!(:action => "show", :id => 123)
|
|
stub(@controller).authorize!(:show, :project) { raise CanCan::AccessDenied }
|
|
resource = CanCan::ControllerResource.new(@controller, :class => false)
|
|
lambda { resource.authorize_resource }.should raise_error(CanCan::AccessDenied)
|
|
end
|
|
|
|
it "should load and authorize using custom instance name" do
|
|
project = Project.create!
|
|
@params.merge!(:action => "show", :id => project.id)
|
|
stub(@controller).authorize!(:show, project) { raise CanCan::AccessDenied }
|
|
resource = CanCan::ControllerResource.new(@controller, :instance_name => :custom_project)
|
|
lambda { resource.load_and_authorize_resource }.should raise_error(CanCan::AccessDenied)
|
|
@controller.instance_variable_get(:@custom_project).should == project
|
|
end
|
|
|
|
it "should load resource using custom find_by attribute" do
|
|
project = Project.create!(:name => "foo")
|
|
@params.merge!(:action => "show", :id => "foo")
|
|
resource = CanCan::ControllerResource.new(@controller, :find_by => :name)
|
|
resource.load_resource
|
|
@controller.instance_variable_get(:@project).should == project
|
|
end
|
|
|
|
it "should raise ImplementationRemoved when adding :name option" do
|
|
lambda {
|
|
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 => Project)
|
|
}.should raise_error(CanCan::ImplementationRemoved)
|
|
end
|
|
|
|
it "should raise ImplementationRemoved exception when passing :nested option" do
|
|
lambda {
|
|
CanCan::ControllerResource.new(@controller, :nested => :project)
|
|
}.should raise_error(CanCan::ImplementationRemoved)
|
|
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
|