marnen-cancan 2.0.0.alpha.pre.f1cebde51a87be149b4970a3287826bb63c0ac0b
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +15 -0
- data/CHANGELOG.rdoc +381 -0
- data/Gemfile +3 -0
- data/LICENSE +20 -0
- data/README.rdoc +108 -0
- data/Rakefile +18 -0
- data/init.rb +1 -0
- data/lib/cancan.rb +13 -0
- data/lib/cancan/ability.rb +348 -0
- data/lib/cancan/controller_additions.rb +392 -0
- data/lib/cancan/controller_resource.rb +265 -0
- data/lib/cancan/exceptions.rb +53 -0
- data/lib/cancan/inherited_resource.rb +20 -0
- data/lib/cancan/matchers.rb +14 -0
- data/lib/cancan/model_adapters/abstract_adapter.rb +56 -0
- data/lib/cancan/model_adapters/active_record_adapter.rb +172 -0
- data/lib/cancan/model_adapters/data_mapper_adapter.rb +34 -0
- data/lib/cancan/model_adapters/default_adapter.rb +7 -0
- data/lib/cancan/model_adapters/mongoid_adapter.rb +54 -0
- data/lib/cancan/model_additions.rb +29 -0
- data/lib/cancan/rule.rb +178 -0
- data/lib/generators/cancan/ability/USAGE +5 -0
- data/lib/generators/cancan/ability/ability_generator.rb +16 -0
- data/lib/generators/cancan/ability/templates/ability.rb +24 -0
- data/lib/generators/cancan/ability/templates/ability_spec.rb +16 -0
- data/lib/generators/cancan/ability/templates/ability_test.rb +10 -0
- data/spec/README.rdoc +28 -0
- data/spec/cancan/ability_spec.rb +541 -0
- data/spec/cancan/controller_additions_spec.rb +118 -0
- data/spec/cancan/controller_resource_spec.rb +535 -0
- data/spec/cancan/exceptions_spec.rb +58 -0
- data/spec/cancan/inherited_resource_spec.rb +58 -0
- data/spec/cancan/matchers_spec.rb +33 -0
- data/spec/cancan/model_adapters/active_record_adapter_spec.rb +278 -0
- data/spec/cancan/model_adapters/data_mapper_adapter_spec.rb +120 -0
- data/spec/cancan/model_adapters/default_adapter_spec.rb +7 -0
- data/spec/cancan/model_adapters/mongoid_adapter_spec.rb +227 -0
- data/spec/cancan/rule_spec.rb +55 -0
- data/spec/matchers.rb +13 -0
- data/spec/spec_helper.rb +49 -0
- metadata +197 -0
@@ -0,0 +1,118 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe CanCan::ControllerAdditions do
|
4
|
+
before(:each) do
|
5
|
+
@params = HashWithIndifferentAccess.new
|
6
|
+
@controller_class = Class.new
|
7
|
+
@controller = @controller_class.new
|
8
|
+
@controller.stub(:params) { @params }
|
9
|
+
@controller.stub(:current_user) { :current_user }
|
10
|
+
@controller_class.should_receive(:helper_method).with(:can?, :cannot?, :current_ability)
|
11
|
+
@controller_class.send(:include, CanCan::ControllerAdditions)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "raises ImplementationRemoved when attempting to call load/authorize/skip/check calls on a controller" do
|
15
|
+
lambda { @controller_class.load_resource }.should raise_error(CanCan::ImplementationRemoved)
|
16
|
+
lambda { @controller_class.authorize_resource }.should raise_error(CanCan::ImplementationRemoved)
|
17
|
+
lambda { @controller_class.skip_load_resource }.should raise_error(CanCan::ImplementationRemoved)
|
18
|
+
lambda { @controller_class.skip_authorize_resource }.should raise_error(CanCan::ImplementationRemoved)
|
19
|
+
lambda { @controller_class.check_authorization }.should raise_error(CanCan::ImplementationRemoved)
|
20
|
+
lambda { @controller_class.skip_authorization_check }.should raise_error(CanCan::ImplementationRemoved)
|
21
|
+
lambda { @controller_class.cancan_skipper }.should raise_error(CanCan::ImplementationRemoved)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "authorize! should pass args to current ability" do
|
25
|
+
@controller.current_ability.should_receive(:authorize!).with(:foo, :bar)
|
26
|
+
@controller.authorize!(:foo, :bar)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "provides a can? and cannot? methods which go through the current ability" do
|
30
|
+
@controller.current_ability.should be_kind_of(Ability)
|
31
|
+
@controller.can?(:foo, :bar).should be_false
|
32
|
+
@controller.cannot?(:foo, :bar).should be_true
|
33
|
+
end
|
34
|
+
|
35
|
+
it "load_and_authorize_resource adds a before filter which passes call to ControllerResource" do
|
36
|
+
controller_resource = double("controller_resource")
|
37
|
+
controller_resource.should_receive(:process)
|
38
|
+
CanCan::ControllerResource.stub(:new).with(@controller, nil, :load => true, :authorize => true, :foo => :bar) { controller_resource }
|
39
|
+
@controller_class.should_receive(:before_filter).with({}).and_yield(@controller)
|
40
|
+
@controller_class.load_and_authorize_resource :foo => :bar
|
41
|
+
end
|
42
|
+
|
43
|
+
it "load_and_authorize_resource passes first argument as the resource name" do
|
44
|
+
controller_resource = double("controller_resource")
|
45
|
+
controller_resource.should_receive(:process)
|
46
|
+
CanCan::ControllerResource.stub(:new).with(@controller, :project, :load => true, :authorize => true, :foo => :bar) { controller_resource }
|
47
|
+
@controller_class.should_receive(:before_filter).with({}).and_yield(@controller)
|
48
|
+
@controller_class.load_and_authorize_resource :project, :foo => :bar
|
49
|
+
end
|
50
|
+
|
51
|
+
it "load_and_authorize_resource passes :only, :except, :if, :unless options to before filter" do
|
52
|
+
controller_resource = double("controller_resource")
|
53
|
+
controller_resource.should_receive(:process)
|
54
|
+
CanCan::ControllerResource.stub(:new).with(@controller, nil, :load => true, :authorize => true) { controller_resource }
|
55
|
+
@controller_class.should_receive(:before_filter).with(:only => 1, :except => 2, :if => 3, :unless => 4).and_yield(@controller)
|
56
|
+
@controller_class.load_and_authorize_resource :only => 1, :except => 2, :if => 3, :unless => 4
|
57
|
+
end
|
58
|
+
|
59
|
+
it "load_and_authorize_resource with :prepend prepends the before filter" do
|
60
|
+
@controller_class.should_receive(:prepend_before_filter).with({})
|
61
|
+
@controller_class.load_and_authorize_resource :foo => :bar, :prepend => true
|
62
|
+
end
|
63
|
+
|
64
|
+
it "cancan_resource_class should be ControllerResource by default" do
|
65
|
+
@controller.class.cancan_resource_class.should == CanCan::ControllerResource
|
66
|
+
end
|
67
|
+
|
68
|
+
it "cancan_resource_class should be InheritedResource when class includes InheritedResources::Actions" do
|
69
|
+
@controller.class.stub(:ancestors) { ["InheritedResources::Actions"] }
|
70
|
+
@controller.class.cancan_resource_class.should == CanCan::InheritedResource
|
71
|
+
end
|
72
|
+
|
73
|
+
it "enable_authorization should call authorize! with controller and action name" do
|
74
|
+
@params.merge!(:controller => "projects", :action => "create")
|
75
|
+
@controller.should_receive(:authorize!).with("create", "projects")
|
76
|
+
@controller_class.stub(:before_filter).with(:only => :foo, :except => :bar).and_yield(@controller)
|
77
|
+
@controller_class.stub(:after_filter).with(:only => :foo, :except => :bar)
|
78
|
+
@controller_class.enable_authorization(:only => :foo, :except => :bar)
|
79
|
+
end
|
80
|
+
|
81
|
+
it "enable_authorization should raise InsufficientAuthorizationCheck when not fully authoried" do
|
82
|
+
@params.merge!(:controller => "projects", :action => "create")
|
83
|
+
@controller_class.stub(:before_filter).with(:only => :foo, :except => :bar)
|
84
|
+
@controller_class.stub(:after_filter).with(:only => :foo, :except => :bar).and_yield(@controller)
|
85
|
+
lambda {
|
86
|
+
@controller_class.enable_authorization(:only => :foo, :except => :bar)
|
87
|
+
}.should raise_error(CanCan::InsufficientAuthorizationCheck)
|
88
|
+
end
|
89
|
+
|
90
|
+
it "enable_authorization should not call authorize! when :if is false" do
|
91
|
+
@authorize_called = false
|
92
|
+
@controller.stub(:authorize?) { false }
|
93
|
+
@controller.stub(:authorize!) { @authorize_called = true }
|
94
|
+
@controller_class.should_receive(:before_filter).with({}).and_yield(@controller)
|
95
|
+
@controller_class.should_receive(:after_filter).with({}).and_yield(@controller)
|
96
|
+
@controller_class.enable_authorization(:if => :authorize?)
|
97
|
+
@authorize_called.should be_false
|
98
|
+
end
|
99
|
+
|
100
|
+
it "enable_authorization should not call authorize! when :unless is true" do
|
101
|
+
@authorize_called = false
|
102
|
+
@controller.stub(:engine_controller?) { true }
|
103
|
+
@controller.stub(:authorize!) { @authorize_called = true }
|
104
|
+
@controller_class.should_receive(:before_filter).with({}).and_yield(@controller)
|
105
|
+
@controller_class.should_receive(:after_filter).with({}).and_yield(@controller)
|
106
|
+
@controller_class.enable_authorization(:unless => :engine_controller?)
|
107
|
+
@authorize_called.should be_false
|
108
|
+
end
|
109
|
+
|
110
|
+
it "enable_authorization should pass block to rescue_from CanCan::Unauthorized call" do
|
111
|
+
@block_called = false
|
112
|
+
@controller_class.should_receive(:before_filter).with({})
|
113
|
+
@controller_class.should_receive(:after_filter).with({})
|
114
|
+
@controller_class.should_receive(:rescue_from).with(CanCan::Unauthorized).and_yield(:exception)
|
115
|
+
@controller_class.enable_authorization { |e| @block_called = (e == :exception) }
|
116
|
+
@block_called.should be_true
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,535 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe CanCan::ControllerResource do
|
4
|
+
before(:each) do
|
5
|
+
Project.delete_all
|
6
|
+
Category.delete_all
|
7
|
+
@params = HashWithIndifferentAccess.new(:controller => "projects")
|
8
|
+
@controller_class = Class.new
|
9
|
+
@controller = @controller_class.new
|
10
|
+
@ability = Ability.new(nil)
|
11
|
+
@controller.stub(:params) { @params }
|
12
|
+
@controller.stub(:current_ability) { @ability }
|
13
|
+
@controller.stub(:authorize!) { |*args| @ability.authorize!(*args) }
|
14
|
+
# @controller_class.stub(:cancan_skipper) { {:authorize => {}, :load => {}} }
|
15
|
+
end
|
16
|
+
|
17
|
+
it "loads the resource into an instance variable if params[:id] is specified" do
|
18
|
+
project = Project.create!
|
19
|
+
@params.merge!(:action => "show", :id => project.id)
|
20
|
+
CanCan::ControllerResource.new(@controller, :load => true).process
|
21
|
+
@controller.instance_variable_get(:@project).should == project
|
22
|
+
end
|
23
|
+
|
24
|
+
it "does not load resource into an instance variable if already set" do
|
25
|
+
@params.merge!(:action => "show", :id => 123)
|
26
|
+
@controller.instance_variable_set(:@project, :some_project)
|
27
|
+
CanCan::ControllerResource.new(@controller, :load => true).process
|
28
|
+
@controller.instance_variable_get(:@project).should == :some_project
|
29
|
+
end
|
30
|
+
|
31
|
+
it "loads resource for namespaced controller" do
|
32
|
+
project = Project.create!
|
33
|
+
@params.merge!(:controller => "admin/projects", :action => "show", :id => project.id)
|
34
|
+
CanCan::ControllerResource.new(@controller, :load => true).process
|
35
|
+
@controller.instance_variable_get(:@project).should == project
|
36
|
+
end
|
37
|
+
|
38
|
+
it "attempts to load a resource with the same namespace as the controller when using :: for namespace" do
|
39
|
+
module SomeEngine
|
40
|
+
class Project < ::Project; end
|
41
|
+
end
|
42
|
+
project = SomeEngine::Project.create!
|
43
|
+
@params.merge!(:controller => "SomeEngine::ProjectsController", :action => "show", :id => project.id)
|
44
|
+
CanCan::ControllerResource.new(@controller, :load => true).process
|
45
|
+
@controller.instance_variable_get(:@project).should == project
|
46
|
+
end
|
47
|
+
|
48
|
+
# Rails includes namespace in params, see issue #349
|
49
|
+
it "creates through the namespaced params" do
|
50
|
+
module SomeEngine
|
51
|
+
class Project < ::Project; end
|
52
|
+
end
|
53
|
+
@params.merge!(:controller => "SomeEngine::ProjectsController", :action => "create", :some_engine_project => {:name => "foobar"})
|
54
|
+
CanCan::ControllerResource.new(@controller, :load => true).process
|
55
|
+
@controller.instance_variable_get(:@project).name.should == "foobar"
|
56
|
+
end
|
57
|
+
|
58
|
+
it "loads resource for namespaced controller when using '::' for namespace" do
|
59
|
+
project = Project.create!
|
60
|
+
@params.merge!(:controller => "Admin::ProjectsController", :action => "show", :id => project.id)
|
61
|
+
CanCan::ControllerResource.new(@controller, :load => true).process
|
62
|
+
@controller.instance_variable_get(:@project).should == project
|
63
|
+
end
|
64
|
+
|
65
|
+
it "has the specified nested resource_class when using / for namespace" do
|
66
|
+
module Admin
|
67
|
+
class Dashboard; end
|
68
|
+
end
|
69
|
+
@ability.can(:index, "admin/dashboard")
|
70
|
+
@params.merge!(:controller => "admin/dashboard", :action => "index")
|
71
|
+
@controller.authorize!(:index, "admin/dashboard")
|
72
|
+
resource = CanCan::ControllerResource.new(@controller, :authorize => true)
|
73
|
+
resource.send(:resource_class).should == Admin::Dashboard
|
74
|
+
end
|
75
|
+
|
76
|
+
it "builds a new resource with hash if params[:id] is not specified and authorize on each attribute" do
|
77
|
+
@params.merge!(:action => "create", :project => {:name => "foobar"})
|
78
|
+
CanCan::ControllerResource.new(@controller, :load => true).process
|
79
|
+
@controller.instance_variable_get(:@project).name.should == "foobar"
|
80
|
+
end
|
81
|
+
|
82
|
+
it "builds a new resource for namespaced model with hash if params[:id] is not specified" do
|
83
|
+
module SomeEngine
|
84
|
+
class Project < ::Project; end
|
85
|
+
end
|
86
|
+
@params.merge!(:action => "create", :some_engine_project => {:name => "foobar"})
|
87
|
+
CanCan::ControllerResource.new(@controller, :load => true, :class => SomeEngine::Project).process
|
88
|
+
@controller.instance_variable_get(:@project).name.should == "foobar"
|
89
|
+
end
|
90
|
+
|
91
|
+
it "builds a new resource with attributes from current ability" do
|
92
|
+
@params.merge!(:action => "new")
|
93
|
+
@ability.can(:create, :projects, :name => "from conditions")
|
94
|
+
CanCan::ControllerResource.new(@controller, :load => true).process
|
95
|
+
@controller.instance_variable_get(:@project).name.should == "from conditions"
|
96
|
+
end
|
97
|
+
|
98
|
+
it "overrides initial attributes with params" do
|
99
|
+
@params.merge!(:action => "new", :project => {:name => "from params"})
|
100
|
+
@ability.can(:create, :projects, :name => "from conditions")
|
101
|
+
CanCan::ControllerResource.new(@controller, :load => true).process
|
102
|
+
@controller.instance_variable_get(:@project).name.should == "from params"
|
103
|
+
end
|
104
|
+
|
105
|
+
it "builds a collection when on index action when class responds to accessible_by and mark ability as fully authorized" do
|
106
|
+
Project.stub(:accessible_by).with(@ability, :index) { :found_projects }
|
107
|
+
@params[:action] = "index"
|
108
|
+
CanCan::ControllerResource.new(@controller, :project, :load => true).process
|
109
|
+
@controller.instance_variable_get(:@project).should be_nil
|
110
|
+
@controller.instance_variable_get(:@projects).should == :found_projects
|
111
|
+
@ability.should be_fully_authorized(:index, :projects)
|
112
|
+
end
|
113
|
+
|
114
|
+
it "does not build a collection when on index action when class does not respond to accessible_by and not mark ability as fully authorized" do
|
115
|
+
class CustomModel
|
116
|
+
end
|
117
|
+
@params[:controller] = "custom_models"
|
118
|
+
@params[:action] = "index"
|
119
|
+
CanCan::ControllerResource.new(@controller, :load => true).process
|
120
|
+
@controller.instance_variable_get(:@project).should be_nil
|
121
|
+
@controller.instance_variable_defined?(:@projects).should be_false
|
122
|
+
@ability.should_not be_fully_authorized(:index, :projects)
|
123
|
+
end
|
124
|
+
|
125
|
+
it "does not use accessible_by when defining abilities through a block" do
|
126
|
+
Project.stub(:accessible_by).with(@ability) { :found_projects }
|
127
|
+
@params[:action] = "index"
|
128
|
+
@ability.can(:read, :projects) { |p| false }
|
129
|
+
CanCan::ControllerResource.new(@controller, :load => true).process
|
130
|
+
@controller.instance_variable_get(:@project).should be_nil
|
131
|
+
@controller.instance_variable_defined?(:@projects).should be_false
|
132
|
+
end
|
133
|
+
|
134
|
+
it "does not authorize resource in collection action" do
|
135
|
+
@params[:action] = "index"
|
136
|
+
@controller.instance_variable_set(:@project, :some_project)
|
137
|
+
@controller.stub(:authorize!).with(:index, :projects) { raise CanCan::Unauthorized }
|
138
|
+
resource = CanCan::ControllerResource.new(@controller, :authorize => true)
|
139
|
+
lambda { resource.process }.should_not raise_error(CanCan::Unauthorized)
|
140
|
+
end
|
141
|
+
|
142
|
+
it "authorizes parent resource in collection action" do
|
143
|
+
@params[:action] = "index"
|
144
|
+
@controller.instance_variable_set(:@category, :some_category)
|
145
|
+
@controller.stub(:authorize!).with(:show, :some_category) { raise CanCan::Unauthorized }
|
146
|
+
resource = CanCan::ControllerResource.new(@controller, :category, :parent => true, :authorize => true)
|
147
|
+
lambda { resource.process }.should raise_error(CanCan::Unauthorized)
|
148
|
+
end
|
149
|
+
|
150
|
+
it "performs authorization using controller action and loaded model" do
|
151
|
+
@params.merge!(:action => "show", :id => 123)
|
152
|
+
@controller.instance_variable_set(:@project, :some_project)
|
153
|
+
@controller.stub(:authorize!).with(:show, :some_project) { raise CanCan::Unauthorized }
|
154
|
+
resource = CanCan::ControllerResource.new(@controller, :authorize => true)
|
155
|
+
lambda { resource.process }.should raise_error(CanCan::Unauthorized)
|
156
|
+
end
|
157
|
+
|
158
|
+
it "does not perform authorization using controller action when no loaded model" do
|
159
|
+
@params.merge!(:action => "show", :id => 123)
|
160
|
+
@controller.stub(:authorize!).with(:show, :projects) { raise CanCan::Unauthorized }
|
161
|
+
resource = CanCan::ControllerResource.new(@controller, :authorize => true)
|
162
|
+
lambda { resource.process }.should_not raise_error(CanCan::Unauthorized)
|
163
|
+
end
|
164
|
+
|
165
|
+
it "does not build a single resource when on custom collection action even with id" do
|
166
|
+
@params.merge!(:action => "sort", :id => 123)
|
167
|
+
CanCan::ControllerResource.new(@controller, :load => true, :collection => [:sort, :list]).process
|
168
|
+
@controller.instance_variable_get(:@project).should be_nil
|
169
|
+
end
|
170
|
+
|
171
|
+
it "loads a collection resource when on custom action with no id param" do
|
172
|
+
Project.stub(:accessible_by).with(@ability, :sort) { :found_projects }
|
173
|
+
@params[:action] = "sort"
|
174
|
+
CanCan::ControllerResource.new(@controller, :load => true).process
|
175
|
+
@controller.instance_variable_get(:@project).should be_nil
|
176
|
+
@controller.instance_variable_get(:@projects).should == :found_projects
|
177
|
+
end
|
178
|
+
|
179
|
+
it "builds a resource when on custom new action even when params[:id] exists" do
|
180
|
+
@params.merge!(:action => "build", :id => 123)
|
181
|
+
Project.stub(:new) { :some_project }
|
182
|
+
CanCan::ControllerResource.new(@controller, :load => true, :new => :build).process
|
183
|
+
@controller.instance_variable_get(:@project).should == :some_project
|
184
|
+
end
|
185
|
+
|
186
|
+
it "does not try to load resource for other action if params[:id] is undefined" do
|
187
|
+
@params[:action] = "list"
|
188
|
+
CanCan::ControllerResource.new(@controller, :load => true).process
|
189
|
+
@controller.instance_variable_get(:@project).should be_nil
|
190
|
+
end
|
191
|
+
|
192
|
+
it "is a parent resource when name is provided which doesn't match controller" do
|
193
|
+
resource = CanCan::ControllerResource.new(@controller, :category)
|
194
|
+
resource.should be_parent
|
195
|
+
end
|
196
|
+
|
197
|
+
it "does not be a parent resource when name is provided which matches controller" do
|
198
|
+
resource = CanCan::ControllerResource.new(@controller, :project)
|
199
|
+
resource.should_not be_parent
|
200
|
+
end
|
201
|
+
|
202
|
+
it "is parent if specified in options" do
|
203
|
+
resource = CanCan::ControllerResource.new(@controller, :project, {:parent => true})
|
204
|
+
resource.should be_parent
|
205
|
+
end
|
206
|
+
|
207
|
+
it "does not be parent if specified in options" do
|
208
|
+
resource = CanCan::ControllerResource.new(@controller, :category, {:parent => false})
|
209
|
+
resource.should_not be_parent
|
210
|
+
end
|
211
|
+
|
212
|
+
it "has the specified resource_class if name is passed to load_resource" do
|
213
|
+
resource = CanCan::ControllerResource.new(@controller, :category)
|
214
|
+
resource.send(:resource_class).should == Category
|
215
|
+
end
|
216
|
+
|
217
|
+
it "loads parent resource through proper id parameter" do
|
218
|
+
project = Project.create!
|
219
|
+
@params.merge!(:action => "index", :project_id => project.id)
|
220
|
+
CanCan::ControllerResource.new(@controller, :project, :load => true, :parent => true).process
|
221
|
+
@controller.instance_variable_get(:@project).should == project
|
222
|
+
end
|
223
|
+
|
224
|
+
it "loads resource through the association of another parent resource using instance variable" do
|
225
|
+
@params.merge!(:action => "show", :id => 123)
|
226
|
+
category = double("category", :projects => double("projects"))
|
227
|
+
category.projects.stub(:find).with(123) { :some_project }
|
228
|
+
@controller.instance_variable_set(:@category, category)
|
229
|
+
CanCan::ControllerResource.new(@controller, :load => true, :through => :category).process
|
230
|
+
@controller.instance_variable_get(:@project).should == :some_project
|
231
|
+
end
|
232
|
+
|
233
|
+
it "loads resource through the custom association name" do
|
234
|
+
@params.merge!(:action => "show", :id => 123)
|
235
|
+
category = double("category", :custom_projects => double("custom_projects"))
|
236
|
+
category.custom_projects.stub(:find).with(123) { :some_project }
|
237
|
+
@controller.instance_variable_set(:@category, category)
|
238
|
+
CanCan::ControllerResource.new(@controller, :load => true, :through => :category, :through_association => :custom_projects).process
|
239
|
+
@controller.instance_variable_get(:@project).should == :some_project
|
240
|
+
end
|
241
|
+
|
242
|
+
it "loads resource through the association of another parent resource using method" do
|
243
|
+
@params.merge!(:action => "show", :id => 123)
|
244
|
+
category = double("category", :projects => double("projects"))
|
245
|
+
@controller.stub(:category) { category }
|
246
|
+
category.projects.stub(:find).with(123) { :some_project }
|
247
|
+
CanCan::ControllerResource.new(@controller, :load => true, :through => :category).process
|
248
|
+
@controller.instance_variable_get(:@project).should == :some_project
|
249
|
+
end
|
250
|
+
|
251
|
+
it "does not load through parent resource if instance isn't loaded when shallow" do
|
252
|
+
project = Project.create!
|
253
|
+
@params.merge!(:action => "show", :id => project.id)
|
254
|
+
CanCan::ControllerResource.new(@controller, :load => true, :through => :category, :shallow => true).process
|
255
|
+
@controller.instance_variable_get(:@project).should == project
|
256
|
+
end
|
257
|
+
|
258
|
+
it "raises Unauthorized when attempting to load resource through nil" do
|
259
|
+
project = Project.create!
|
260
|
+
@params.merge!(:action => "show", :id => project.id)
|
261
|
+
resource = CanCan::ControllerResource.new(@controller, :load => true, :through => :category)
|
262
|
+
lambda {
|
263
|
+
resource.process
|
264
|
+
}.should raise_error(CanCan::Unauthorized) { |exception|
|
265
|
+
exception.action.should == :show
|
266
|
+
exception.subject.should == :projects
|
267
|
+
}
|
268
|
+
@controller.instance_variable_get(:@project).should be_nil
|
269
|
+
end
|
270
|
+
|
271
|
+
it "named resources should be loaded independently of the controller name" do
|
272
|
+
category = Category.create!
|
273
|
+
@params.merge!(:action => "new", :category_id => category.id)
|
274
|
+
CanCan::ControllerResource.new(@controller, :category, :load => true).process
|
275
|
+
CanCan::ControllerResource.new(@controller, :project, :load => true, :through => :category).process
|
276
|
+
@controller.instance_variable_get(:@category).should eq(category)
|
277
|
+
project = @controller.instance_variable_get(:@project)
|
278
|
+
project.category.should eq(category)
|
279
|
+
end
|
280
|
+
|
281
|
+
it "parent resources shouldn't be altered" do
|
282
|
+
category = Category.create!
|
283
|
+
@params.merge!(:action => "create", :category_id => category.id, :project => { :name => 'foo' })
|
284
|
+
CanCan::ControllerResource.new(@controller, :category, :load => true).process
|
285
|
+
CanCan::ControllerResource.new(@controller, :project, :load => true, :through => :category).process
|
286
|
+
project = @controller.instance_variable_get(:@project)
|
287
|
+
project.new_record?.should eq(true)
|
288
|
+
project.name.should eq('foo')
|
289
|
+
end
|
290
|
+
|
291
|
+
it "authorizes nested resource through parent association on index action" do
|
292
|
+
pending
|
293
|
+
@params.merge!(:action => "index")
|
294
|
+
category = Object.new
|
295
|
+
@controller.instance_variable_set(:@category, category)
|
296
|
+
@controller.stub(:authorize!).with(:index, category => :projects) { raise CanCan::Unauthorized }
|
297
|
+
resource = CanCan::ControllerResource.new(@controller, :authorize => true, :through => :category)
|
298
|
+
lambda { resource.process }.should raise_error(CanCan::Unauthorized)
|
299
|
+
end
|
300
|
+
|
301
|
+
it "loads through first matching if multiple are given" do
|
302
|
+
@params.merge!(:action => "show", :id => 123)
|
303
|
+
category = double("category", :projects => double("projects"))
|
304
|
+
category.projects.stub(:find).with(123) { :some_project }
|
305
|
+
@controller.instance_variable_set(:@category, category)
|
306
|
+
CanCan::ControllerResource.new(@controller, :load => true, :through => [:category, :user]).process
|
307
|
+
@controller.instance_variable_get(:@project).should == :some_project
|
308
|
+
end
|
309
|
+
|
310
|
+
it "finds record through has_one association with :singleton option without id param" do
|
311
|
+
@params.merge!(:action => "show", :id => nil)
|
312
|
+
category = Object.new
|
313
|
+
@controller.instance_variable_set(:@category, category)
|
314
|
+
category.stub(:project) { :some_project }
|
315
|
+
CanCan::ControllerResource.new(@controller, :load => true, :through => :category, :singleton => true).process
|
316
|
+
@controller.instance_variable_get(:@project).should == :some_project
|
317
|
+
end
|
318
|
+
|
319
|
+
it "does not build record through has_one association with :singleton option because it can cause it to delete it in the database" do
|
320
|
+
@params.merge!(:action => "create", :project => {:name => "foobar"})
|
321
|
+
category = Category.new
|
322
|
+
@controller.instance_variable_set(:@category, category)
|
323
|
+
CanCan::ControllerResource.new(@controller, :load => true, :through => :category, :singleton => true).process
|
324
|
+
@controller.instance_variable_get(:@project).name.should == "foobar"
|
325
|
+
@controller.instance_variable_get(:@project).category.should == category
|
326
|
+
end
|
327
|
+
|
328
|
+
it "finds record through has_one association with :singleton and :shallow options" do
|
329
|
+
project = Project.create!
|
330
|
+
@params.merge!(:action => "show", :id => project.id)
|
331
|
+
CanCan::ControllerResource.new(@controller, :load => true, :through => :category, :singleton => true, :shallow => true).process
|
332
|
+
@controller.instance_variable_get(:@project).should == project
|
333
|
+
end
|
334
|
+
|
335
|
+
it "builds record through has_one association with :singleton and :shallow options" do
|
336
|
+
@params.merge!(:action => "create", :project => {:name => "foobar"})
|
337
|
+
CanCan::ControllerResource.new(@controller, :load => true, :through => :category, :singleton => true, :shallow => true).process
|
338
|
+
@controller.instance_variable_get(:@project).name.should == "foobar"
|
339
|
+
end
|
340
|
+
|
341
|
+
it "only authorizes :show action on parent resource" do
|
342
|
+
project = Project.create!
|
343
|
+
@params.merge!(:action => "new", :project_id => project.id)
|
344
|
+
@controller.stub(:authorize!).with(:show, project) { raise CanCan::Unauthorized }
|
345
|
+
resource = CanCan::ControllerResource.new(@controller, :project, :load => true, :authorize => true, :parent => true)
|
346
|
+
lambda { resource.process }.should raise_error(CanCan::Unauthorized)
|
347
|
+
end
|
348
|
+
|
349
|
+
it "authorizes update action before setting attributes" do
|
350
|
+
@ability.can :update, :projects, :name => "bar"
|
351
|
+
project = Project.create!(:name => "foo")
|
352
|
+
@params.merge!(:action => "update", :id => project.id, :project => {:name => "bar"})
|
353
|
+
resource = CanCan::ControllerResource.new(@controller, :project, :load => true, :authorize => true)
|
354
|
+
lambda { resource.process }.should raise_error(CanCan::Unauthorized)
|
355
|
+
end
|
356
|
+
|
357
|
+
it "authorizes update action after setting attributes" do
|
358
|
+
@ability.can :update, :projects, :name => "foo"
|
359
|
+
project = Project.create!(:name => "foo")
|
360
|
+
@params.merge!(:action => "update", :id => project.id, :project => {:name => "bar"})
|
361
|
+
resource = CanCan::ControllerResource.new(@controller, :project, :load => true, :authorize => true)
|
362
|
+
lambda { resource.process }.should raise_error(CanCan::Unauthorized)
|
363
|
+
end
|
364
|
+
|
365
|
+
it "loads the model using a custom class" do
|
366
|
+
project = Project.create!
|
367
|
+
@params.merge!(:action => "show", :id => project.id)
|
368
|
+
CanCan::ControllerResource.new(@controller, :load => true, :class => Project).process
|
369
|
+
@controller.instance_variable_get(:@project).should == project
|
370
|
+
end
|
371
|
+
|
372
|
+
it "loads the model using a custom namespaced class" do
|
373
|
+
module SomeEngine
|
374
|
+
class Project < ::Project; end
|
375
|
+
end
|
376
|
+
project = SomeEngine::Project.create!
|
377
|
+
@params.merge!(:action => "show", :id => project.id)
|
378
|
+
CanCan::ControllerResource.new(@controller, :load => true, :class => SomeEngine::Project).process
|
379
|
+
@controller.instance_variable_get(:@project).should == project
|
380
|
+
end
|
381
|
+
|
382
|
+
it "does not authorize based on resource name if class is false because we don't do class level authorization anymore" do
|
383
|
+
@params.merge!(:action => "show", :id => 123)
|
384
|
+
@controller.stub(:authorize!).with(:show, :projects) { raise CanCan::Unauthorized }
|
385
|
+
resource = CanCan::ControllerResource.new(@controller, :authorize => true, :class => false)
|
386
|
+
lambda { resource.process }.should_not raise_error(CanCan::Unauthorized)
|
387
|
+
end
|
388
|
+
|
389
|
+
it "loads and authorize using custom instance name" do
|
390
|
+
project = Project.create!
|
391
|
+
@params.merge!(:action => "show", :id => project.id)
|
392
|
+
@controller.stub(:authorize!).with(:show, project) { raise CanCan::Unauthorized }
|
393
|
+
resource = CanCan::ControllerResource.new(@controller, :load => true, :authorize => true, :instance_name => :custom_project)
|
394
|
+
lambda { resource.process }.should raise_error(CanCan::Unauthorized)
|
395
|
+
@controller.instance_variable_get(:@custom_project).should == project
|
396
|
+
end
|
397
|
+
|
398
|
+
it "loads resource using custom ID param" do
|
399
|
+
project = Project.create!
|
400
|
+
@params.merge!(:action => "show", :the_project => project.id)
|
401
|
+
resource = CanCan::ControllerResource.new(@controller, :id_param => :the_project, :load => true)
|
402
|
+
resource.process
|
403
|
+
@controller.instance_variable_get(:@project).should == project
|
404
|
+
end
|
405
|
+
|
406
|
+
it "loads resource using custom find_by attribute" do
|
407
|
+
project = Project.create!(:name => "foo")
|
408
|
+
@params.merge!(:action => "show", :id => "foo")
|
409
|
+
CanCan::ControllerResource.new(@controller, :load => true, :find_by => :name).process
|
410
|
+
@controller.instance_variable_get(:@project).should == project
|
411
|
+
end
|
412
|
+
|
413
|
+
it "authorizes each new attribute in the create action" do
|
414
|
+
@params.merge!(:action => "create", :project => {:name => "foo"})
|
415
|
+
@controller.instance_variable_set(:@project, :some_project)
|
416
|
+
@ability.should_receive(:authorize!).with(:create, :some_project, :name)
|
417
|
+
CanCan::ControllerResource.new(@controller, :authorize => true).process
|
418
|
+
end
|
419
|
+
|
420
|
+
it "allows full find method to be passed into find_by option" do
|
421
|
+
project = Project.create!(:name => "foo")
|
422
|
+
@params.merge!(:action => "show", :id => "foo")
|
423
|
+
CanCan::ControllerResource.new(@controller, :find_by => :find_by_name, :load => true).process
|
424
|
+
@controller.instance_variable_get(:@project).should == project
|
425
|
+
end
|
426
|
+
|
427
|
+
it "authorizes each new attribute in the update action" do
|
428
|
+
@params.merge!(:action => "update", :id => 123, :project => {:name => "foo"})
|
429
|
+
@controller.instance_variable_set(:@project, :some_project)
|
430
|
+
@ability.should_receive(:authorize!).with(:update, :some_project, :name)
|
431
|
+
CanCan::ControllerResource.new(@controller, :authorize => true).process
|
432
|
+
end
|
433
|
+
|
434
|
+
it "fetches member through method when instance variable is not provided" do
|
435
|
+
@controller.stub(:project) { :some_project }
|
436
|
+
@params.merge!(:action => "show", :id => 123)
|
437
|
+
@controller.stub(:authorize!).with(:show, :some_project) { raise CanCan::Unauthorized }
|
438
|
+
resource = CanCan::ControllerResource.new(@controller, :authorize => true)
|
439
|
+
lambda { resource.process }.should raise_error(CanCan::Unauthorized)
|
440
|
+
end
|
441
|
+
|
442
|
+
it "attempts to load a resource with the same namespace as the controller when using :: for namespace" do
|
443
|
+
module Namespaced
|
444
|
+
class Project < ::Project; end
|
445
|
+
end
|
446
|
+
project = Namespaced::Project.create!
|
447
|
+
@params.merge!(:controller => "Namespaced::ProjectsController", :action => "show", :id => project.id)
|
448
|
+
CanCan::ControllerResource.new(@controller, :load => true).process
|
449
|
+
@controller.instance_variable_get(:@project).should == project
|
450
|
+
end
|
451
|
+
|
452
|
+
# Rails includes namespace in params, see issue #349
|
453
|
+
it "creates through namespaced params" do
|
454
|
+
module Namespaced
|
455
|
+
class Project < ::Project; end
|
456
|
+
end
|
457
|
+
@params.merge!(:controller => "Namespaced::ProjectsController", :action => "create", :namespaced_project => {:name => "foobar"})
|
458
|
+
CanCan::ControllerResource.new(@controller, :load => true).process
|
459
|
+
@controller.instance_variable_get(:@project).name.should == "foobar"
|
460
|
+
end
|
461
|
+
|
462
|
+
it "should properly authorize resource for namespaced controller" do
|
463
|
+
@ability.can(:index, "admin/dashboard")
|
464
|
+
@params.merge!(:controller => "admin/dashboard", :action => "index")
|
465
|
+
@controller.authorize!(:index, "admin/dashboard")
|
466
|
+
resource = CanCan::ControllerResource.new(@controller, :authorize => true).process
|
467
|
+
lambda { resource.process }.should_not raise_error(CanCan::Unauthorized)
|
468
|
+
end
|
469
|
+
|
470
|
+
# it "raises ImplementationRemoved when adding :name option" do
|
471
|
+
# lambda {
|
472
|
+
# CanCan::ControllerResource.new(@controller, :name => :foo)
|
473
|
+
# }.should raise_error(CanCan::ImplementationRemoved)
|
474
|
+
# end
|
475
|
+
#
|
476
|
+
# it "raises ImplementationRemoved exception when specifying :resource option since it is no longer used" do
|
477
|
+
# lambda {
|
478
|
+
# CanCan::ControllerResource.new(@controller, :resource => Project)
|
479
|
+
# }.should raise_error(CanCan::ImplementationRemoved)
|
480
|
+
# end
|
481
|
+
#
|
482
|
+
# it "raises ImplementationRemoved exception when passing :nested option" do
|
483
|
+
# lambda {
|
484
|
+
# CanCan::ControllerResource.new(@controller, :nested => :project)
|
485
|
+
# }.should raise_error(CanCan::ImplementationRemoved)
|
486
|
+
# end
|
487
|
+
|
488
|
+
# it "skips resource behavior for :only actions in array" do
|
489
|
+
# @controller_class.stub(:cancan_skipper) { {:load => {nil => {:only => [:index, :show]}}} }
|
490
|
+
# @params.merge!(:action => "index")
|
491
|
+
# CanCan::ControllerResource.new(@controller).skip?(:load).should be_true
|
492
|
+
# CanCan::ControllerResource.new(@controller, :some_resource).skip?(:load).should be_false
|
493
|
+
# @params.merge!(:action => "show")
|
494
|
+
# CanCan::ControllerResource.new(@controller).skip?(:load).should be_true
|
495
|
+
# @params.merge!(:action => "other_action")
|
496
|
+
# CanCan::ControllerResource.new(@controller).skip?(:load).should be_false
|
497
|
+
# end
|
498
|
+
#
|
499
|
+
# it "skips resource behavior for :only one action on resource" do
|
500
|
+
# @controller_class.stub(:cancan_skipper) { {:authorize => {:project => {:only => :index}}} }
|
501
|
+
# @params.merge!(:action => "index")
|
502
|
+
# CanCan::ControllerResource.new(@controller).skip?(:authorize).should be_false
|
503
|
+
# CanCan::ControllerResource.new(@controller, :project).skip?(:authorize).should be_true
|
504
|
+
# @params.merge!(:action => "other_action")
|
505
|
+
# CanCan::ControllerResource.new(@controller, :project).skip?(:authorize).should be_false
|
506
|
+
# end
|
507
|
+
#
|
508
|
+
# it "skips resource behavior :except actions in array" do
|
509
|
+
# @controller_class.stub(:cancan_skipper) { {:load => {nil => {:except => [:index, :show]}}} }
|
510
|
+
# @params.merge!(:action => "index")
|
511
|
+
# CanCan::ControllerResource.new(@controller).skip?(:load).should be_false
|
512
|
+
# @params.merge!(:action => "show")
|
513
|
+
# CanCan::ControllerResource.new(@controller).skip?(:load).should be_false
|
514
|
+
# @params.merge!(:action => "other_action")
|
515
|
+
# CanCan::ControllerResource.new(@controller).skip?(:load).should be_true
|
516
|
+
# CanCan::ControllerResource.new(@controller, :some_resource).skip?(:load).should be_false
|
517
|
+
# end
|
518
|
+
#
|
519
|
+
# it "skips resource behavior :except one action on resource" do
|
520
|
+
# @controller_class.stub(:cancan_skipper) { {:authorize => {:project => {:except => :index}}} }
|
521
|
+
# @params.merge!(:action => "index")
|
522
|
+
# CanCan::ControllerResource.new(@controller, :project).skip?(:authorize).should be_false
|
523
|
+
# @params.merge!(:action => "other_action")
|
524
|
+
# CanCan::ControllerResource.new(@controller).skip?(:authorize).should be_false
|
525
|
+
# CanCan::ControllerResource.new(@controller, :project).skip?(:authorize).should be_true
|
526
|
+
# end
|
527
|
+
#
|
528
|
+
# it "skips loading and authorization" do
|
529
|
+
# @controller_class.stub(:cancan_skipper) { {:authorize => {nil => {}}, :load => {nil => {}}} }
|
530
|
+
# @params.merge!(:action => "new")
|
531
|
+
# resource = CanCan::ControllerResource.new(@controller)
|
532
|
+
# lambda { resource.load_and_authorize_resource }.should_not raise_error
|
533
|
+
# @controller.instance_variable_get(:@project).should be_nil
|
534
|
+
# end
|
535
|
+
end
|