culturecode-cancan 2.0.0.alpha

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.rdoc +381 -0
  3. data/Gemfile +3 -0
  4. data/LICENSE +20 -0
  5. data/README.rdoc +108 -0
  6. data/Rakefile +18 -0
  7. data/init.rb +1 -0
  8. data/lib/cancan.rb +13 -0
  9. data/lib/cancan/ability.rb +348 -0
  10. data/lib/cancan/controller_additions.rb +392 -0
  11. data/lib/cancan/controller_resource.rb +266 -0
  12. data/lib/cancan/exceptions.rb +53 -0
  13. data/lib/cancan/inherited_resource.rb +20 -0
  14. data/lib/cancan/matchers.rb +14 -0
  15. data/lib/cancan/model_adapters/abstract_adapter.rb +56 -0
  16. data/lib/cancan/model_adapters/active_record_adapter.rb +172 -0
  17. data/lib/cancan/model_adapters/data_mapper_adapter.rb +34 -0
  18. data/lib/cancan/model_adapters/default_adapter.rb +7 -0
  19. data/lib/cancan/model_adapters/mongoid_adapter.rb +54 -0
  20. data/lib/cancan/model_additions.rb +29 -0
  21. data/lib/cancan/rule.rb +178 -0
  22. data/lib/generators/cancan/ability/USAGE +5 -0
  23. data/lib/generators/cancan/ability/ability_generator.rb +16 -0
  24. data/lib/generators/cancan/ability/templates/ability.rb +24 -0
  25. data/lib/generators/cancan/ability/templates/ability_spec.rb +16 -0
  26. data/lib/generators/cancan/ability/templates/ability_test.rb +10 -0
  27. data/spec/README.rdoc +28 -0
  28. data/spec/cancan/ability_spec.rb +541 -0
  29. data/spec/cancan/controller_additions_spec.rb +118 -0
  30. data/spec/cancan/controller_resource_spec.rb +551 -0
  31. data/spec/cancan/exceptions_spec.rb +58 -0
  32. data/spec/cancan/inherited_resource_spec.rb +58 -0
  33. data/spec/cancan/matchers_spec.rb +33 -0
  34. data/spec/cancan/model_adapters/active_record_adapter_spec.rb +278 -0
  35. data/spec/cancan/model_adapters/data_mapper_adapter_spec.rb +120 -0
  36. data/spec/cancan/model_adapters/default_adapter_spec.rb +7 -0
  37. data/spec/cancan/model_adapters/mongoid_adapter_spec.rb +226 -0
  38. data/spec/cancan/rule_spec.rb +55 -0
  39. data/spec/matchers.rb +13 -0
  40. data/spec/spec_helper.rb +49 -0
  41. metadata +194 -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,551 @@
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.should be_new_record
288
+ project.name.should eq('foo')
289
+ end
290
+
291
+ it "does not overrides an attribute if it is based on parent resource" do
292
+ user = double('user')
293
+ user.should_receive(:category_id).and_return nil
294
+ @ability = Ability.new user
295
+ @ability.can :new, :projects, :category_id => user.category_id
296
+ category = Category.create!
297
+ @controller.instance_variable_set(:@category, category)
298
+
299
+ @params.merge! :action => 'new', :category_id => category.id
300
+ CanCan::ControllerResource.new(@controller, :category, :load => true).process
301
+ CanCan::ControllerResource.new(@controller, :project, :load => true, :through => :category, :singleton => true).process
302
+ project = @controller.instance_variable_get(:@project)
303
+ project.category_id.should_not be_nil
304
+ project.category.should eq(category)
305
+ end
306
+
307
+ it "authorizes nested resource through parent association on index action" do
308
+ pending
309
+ @params.merge!(:action => "index")
310
+ category = Object.new
311
+ @controller.instance_variable_set(:@category, category)
312
+ @controller.stub(:authorize!).with(:index, category => :projects) { raise CanCan::Unauthorized }
313
+ resource = CanCan::ControllerResource.new(@controller, :authorize => true, :through => :category)
314
+ lambda { resource.process }.should raise_error(CanCan::Unauthorized)
315
+ end
316
+
317
+ it "loads through first matching if multiple are given" do
318
+ @params.merge!(:action => "show", :id => 123)
319
+ category = double("category", :projects => double("projects"))
320
+ category.projects.stub(:find).with(123) { :some_project }
321
+ @controller.instance_variable_set(:@category, category)
322
+ CanCan::ControllerResource.new(@controller, :load => true, :through => [:category, :user]).process
323
+ @controller.instance_variable_get(:@project).should == :some_project
324
+ end
325
+
326
+ it "finds record through has_one association with :singleton option without id param" do
327
+ @params.merge!(:action => "show", :id => nil)
328
+ category = Object.new
329
+ @controller.instance_variable_set(:@category, category)
330
+ category.stub(:project) { :some_project }
331
+ CanCan::ControllerResource.new(@controller, :load => true, :through => :category, :singleton => true).process
332
+ @controller.instance_variable_get(:@project).should == :some_project
333
+ end
334
+
335
+ it "does not build record through has_one association with :singleton option because it can cause it to delete it in the database" do
336
+ @params.merge!(:action => "create", :project => {:name => "foobar"})
337
+ category = Category.new
338
+ @controller.instance_variable_set(:@category, category)
339
+ CanCan::ControllerResource.new(@controller, :load => true, :through => :category, :singleton => true).process
340
+ @controller.instance_variable_get(:@project).name.should == "foobar"
341
+ @controller.instance_variable_get(:@project).category.should == category
342
+ end
343
+
344
+ it "finds record through has_one association with :singleton and :shallow options" do
345
+ project = Project.create!
346
+ @params.merge!(:action => "show", :id => project.id)
347
+ CanCan::ControllerResource.new(@controller, :load => true, :through => :category, :singleton => true, :shallow => true).process
348
+ @controller.instance_variable_get(:@project).should == project
349
+ end
350
+
351
+ it "builds record through has_one association with :singleton and :shallow options" do
352
+ @params.merge!(:action => "create", :project => {:name => "foobar"})
353
+ CanCan::ControllerResource.new(@controller, :load => true, :through => :category, :singleton => true, :shallow => true).process
354
+ @controller.instance_variable_get(:@project).name.should == "foobar"
355
+ end
356
+
357
+ it "only authorizes :show action on parent resource" do
358
+ project = Project.create!
359
+ @params.merge!(:action => "new", :project_id => project.id)
360
+ @controller.stub(:authorize!).with(:show, project) { raise CanCan::Unauthorized }
361
+ resource = CanCan::ControllerResource.new(@controller, :project, :load => true, :authorize => true, :parent => true)
362
+ lambda { resource.process }.should raise_error(CanCan::Unauthorized)
363
+ end
364
+
365
+ it "authorizes update action before setting attributes" do
366
+ @ability.can :update, :projects, :name => "bar"
367
+ project = Project.create!(:name => "foo")
368
+ @params.merge!(:action => "update", :id => project.id, :project => {:name => "bar"})
369
+ resource = CanCan::ControllerResource.new(@controller, :project, :load => true, :authorize => true)
370
+ lambda { resource.process }.should raise_error(CanCan::Unauthorized)
371
+ end
372
+
373
+ it "authorizes update action after setting attributes" do
374
+ @ability.can :update, :projects, :name => "foo"
375
+ project = Project.create!(:name => "foo")
376
+ @params.merge!(:action => "update", :id => project.id, :project => {:name => "bar"})
377
+ resource = CanCan::ControllerResource.new(@controller, :project, :load => true, :authorize => true)
378
+ lambda { resource.process }.should raise_error(CanCan::Unauthorized)
379
+ end
380
+
381
+ it "loads the model using a custom class" do
382
+ project = Project.create!
383
+ @params.merge!(:action => "show", :id => project.id)
384
+ CanCan::ControllerResource.new(@controller, :load => true, :class => Project).process
385
+ @controller.instance_variable_get(:@project).should == project
386
+ end
387
+
388
+ it "loads the model using a custom namespaced class" do
389
+ module SomeEngine
390
+ class Project < ::Project; end
391
+ end
392
+ project = SomeEngine::Project.create!
393
+ @params.merge!(:action => "show", :id => project.id)
394
+ CanCan::ControllerResource.new(@controller, :load => true, :class => SomeEngine::Project).process
395
+ @controller.instance_variable_get(:@project).should == project
396
+ end
397
+
398
+ it "does not authorize based on resource name if class is false because we don't do class level authorization anymore" do
399
+ @params.merge!(:action => "show", :id => 123)
400
+ @controller.stub(:authorize!).with(:show, :projects) { raise CanCan::Unauthorized }
401
+ resource = CanCan::ControllerResource.new(@controller, :authorize => true, :class => false)
402
+ lambda { resource.process }.should_not raise_error(CanCan::Unauthorized)
403
+ end
404
+
405
+ it "loads and authorize using custom instance name" do
406
+ project = Project.create!
407
+ @params.merge!(:action => "show", :id => project.id)
408
+ @controller.stub(:authorize!).with(:show, project) { raise CanCan::Unauthorized }
409
+ resource = CanCan::ControllerResource.new(@controller, :load => true, :authorize => true, :instance_name => :custom_project)
410
+ lambda { resource.process }.should raise_error(CanCan::Unauthorized)
411
+ @controller.instance_variable_get(:@custom_project).should == project
412
+ end
413
+
414
+ it "loads resource using custom ID param" do
415
+ project = Project.create!
416
+ @params.merge!(:action => "show", :the_project => project.id)
417
+ resource = CanCan::ControllerResource.new(@controller, :id_param => :the_project, :load => true)
418
+ resource.process
419
+ @controller.instance_variable_get(:@project).should == project
420
+ end
421
+
422
+ it "loads resource using custom find_by attribute" do
423
+ project = Project.create!(:name => "foo")
424
+ @params.merge!(:action => "show", :id => "foo")
425
+ CanCan::ControllerResource.new(@controller, :load => true, :find_by => :name).process
426
+ @controller.instance_variable_get(:@project).should == project
427
+ end
428
+
429
+ it "authorizes each new attribute in the create action" do
430
+ @params.merge!(:action => "create", :project => {:name => "foo"})
431
+ @controller.instance_variable_set(:@project, :some_project)
432
+ @ability.should_receive(:authorize!).with(:create, :some_project, :name)
433
+ CanCan::ControllerResource.new(@controller, :authorize => true).process
434
+ end
435
+
436
+ it "allows full find method to be passed into find_by option" do
437
+ project = Project.create!(:name => "foo")
438
+ @params.merge!(:action => "show", :id => "foo")
439
+ CanCan::ControllerResource.new(@controller, :find_by => :find_by_name, :load => true).process
440
+ @controller.instance_variable_get(:@project).should == project
441
+ end
442
+
443
+ it "authorizes each new attribute in the update action" do
444
+ @params.merge!(:action => "update", :id => 123, :project => {:name => "foo"})
445
+ @controller.instance_variable_set(:@project, :some_project)
446
+ @ability.should_receive(:authorize!).with(:update, :some_project, :name)
447
+ CanCan::ControllerResource.new(@controller, :authorize => true).process
448
+ end
449
+
450
+ it "fetches member through method when instance variable is not provided" do
451
+ @controller.stub(:project) { :some_project }
452
+ @params.merge!(:action => "show", :id => 123)
453
+ @controller.stub(:authorize!).with(:show, :some_project) { raise CanCan::Unauthorized }
454
+ resource = CanCan::ControllerResource.new(@controller, :authorize => true)
455
+ lambda { resource.process }.should raise_error(CanCan::Unauthorized)
456
+ end
457
+
458
+ it "attempts to load a resource with the same namespace as the controller when using :: for namespace" do
459
+ module Namespaced
460
+ class Project < ::Project; end
461
+ end
462
+ project = Namespaced::Project.create!
463
+ @params.merge!(:controller => "Namespaced::ProjectsController", :action => "show", :id => project.id)
464
+ CanCan::ControllerResource.new(@controller, :load => true).process
465
+ @controller.instance_variable_get(:@project).should == project
466
+ end
467
+
468
+ # Rails includes namespace in params, see issue #349
469
+ it "creates through namespaced params" do
470
+ module Namespaced
471
+ class Project < ::Project; end
472
+ end
473
+ @params.merge!(:controller => "Namespaced::ProjectsController", :action => "create", :namespaced_project => {:name => "foobar"})
474
+ CanCan::ControllerResource.new(@controller, :load => true).process
475
+ @controller.instance_variable_get(:@project).name.should == "foobar"
476
+ end
477
+
478
+ it "should properly authorize resource for namespaced controller" do
479
+ @ability.can(:index, "admin/dashboard")
480
+ @params.merge!(:controller => "admin/dashboard", :action => "index")
481
+ @controller.authorize!(:index, "admin/dashboard")
482
+ resource = CanCan::ControllerResource.new(@controller, :authorize => true).process
483
+ lambda { resource.process }.should_not raise_error(CanCan::Unauthorized)
484
+ end
485
+
486
+ # it "raises ImplementationRemoved when adding :name option" do
487
+ # lambda {
488
+ # CanCan::ControllerResource.new(@controller, :name => :foo)
489
+ # }.should raise_error(CanCan::ImplementationRemoved)
490
+ # end
491
+ #
492
+ # it "raises ImplementationRemoved exception when specifying :resource option since it is no longer used" do
493
+ # lambda {
494
+ # CanCan::ControllerResource.new(@controller, :resource => Project)
495
+ # }.should raise_error(CanCan::ImplementationRemoved)
496
+ # end
497
+ #
498
+ # it "raises ImplementationRemoved exception when passing :nested option" do
499
+ # lambda {
500
+ # CanCan::ControllerResource.new(@controller, :nested => :project)
501
+ # }.should raise_error(CanCan::ImplementationRemoved)
502
+ # end
503
+
504
+ # it "skips resource behavior for :only actions in array" do
505
+ # @controller_class.stub(:cancan_skipper) { {:load => {nil => {:only => [:index, :show]}}} }
506
+ # @params.merge!(:action => "index")
507
+ # CanCan::ControllerResource.new(@controller).skip?(:load).should be_true
508
+ # CanCan::ControllerResource.new(@controller, :some_resource).skip?(:load).should be_false
509
+ # @params.merge!(:action => "show")
510
+ # CanCan::ControllerResource.new(@controller).skip?(:load).should be_true
511
+ # @params.merge!(:action => "other_action")
512
+ # CanCan::ControllerResource.new(@controller).skip?(:load).should be_false
513
+ # end
514
+ #
515
+ # it "skips resource behavior for :only one action on resource" do
516
+ # @controller_class.stub(:cancan_skipper) { {:authorize => {:project => {:only => :index}}} }
517
+ # @params.merge!(:action => "index")
518
+ # CanCan::ControllerResource.new(@controller).skip?(:authorize).should be_false
519
+ # CanCan::ControllerResource.new(@controller, :project).skip?(:authorize).should be_true
520
+ # @params.merge!(:action => "other_action")
521
+ # CanCan::ControllerResource.new(@controller, :project).skip?(:authorize).should be_false
522
+ # end
523
+ #
524
+ # it "skips resource behavior :except actions in array" do
525
+ # @controller_class.stub(:cancan_skipper) { {:load => {nil => {:except => [:index, :show]}}} }
526
+ # @params.merge!(:action => "index")
527
+ # CanCan::ControllerResource.new(@controller).skip?(:load).should be_false
528
+ # @params.merge!(:action => "show")
529
+ # CanCan::ControllerResource.new(@controller).skip?(:load).should be_false
530
+ # @params.merge!(:action => "other_action")
531
+ # CanCan::ControllerResource.new(@controller).skip?(:load).should be_true
532
+ # CanCan::ControllerResource.new(@controller, :some_resource).skip?(:load).should be_false
533
+ # end
534
+ #
535
+ # it "skips resource behavior :except one action on resource" do
536
+ # @controller_class.stub(:cancan_skipper) { {:authorize => {:project => {:except => :index}}} }
537
+ # @params.merge!(:action => "index")
538
+ # CanCan::ControllerResource.new(@controller, :project).skip?(:authorize).should be_false
539
+ # @params.merge!(:action => "other_action")
540
+ # CanCan::ControllerResource.new(@controller).skip?(:authorize).should be_false
541
+ # CanCan::ControllerResource.new(@controller, :project).skip?(:authorize).should be_true
542
+ # end
543
+ #
544
+ # it "skips loading and authorization" do
545
+ # @controller_class.stub(:cancan_skipper) { {:authorize => {nil => {}}, :load => {nil => {}}} }
546
+ # @params.merge!(:action => "new")
547
+ # resource = CanCan::ControllerResource.new(@controller)
548
+ # lambda { resource.load_and_authorize_resource }.should_not raise_error
549
+ # @controller.instance_variable_get(:@project).should be_nil
550
+ # end
551
+ end