cancancan 1.10.0 → 3.5.0

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.
Files changed (87) hide show
  1. checksums.yaml +5 -5
  2. data/cancancan.gemspec +19 -21
  3. data/init.rb +2 -0
  4. data/lib/cancan/ability/actions.rb +93 -0
  5. data/lib/cancan/ability/rules.rb +96 -0
  6. data/lib/cancan/ability/strong_parameter_support.rb +41 -0
  7. data/lib/cancan/ability.rb +114 -146
  8. data/lib/cancan/class_matcher.rb +30 -0
  9. data/lib/cancan/conditions_matcher.rb +147 -0
  10. data/lib/cancan/config.rb +101 -0
  11. data/lib/cancan/controller_additions.rb +38 -41
  12. data/lib/cancan/controller_resource.rb +59 -215
  13. data/lib/cancan/controller_resource_builder.rb +26 -0
  14. data/lib/cancan/controller_resource_finder.rb +42 -0
  15. data/lib/cancan/controller_resource_loader.rb +120 -0
  16. data/lib/cancan/controller_resource_name_finder.rb +23 -0
  17. data/lib/cancan/controller_resource_sanitizer.rb +32 -0
  18. data/lib/cancan/exceptions.rb +25 -5
  19. data/lib/cancan/matchers.rb +17 -3
  20. data/lib/cancan/model_adapters/abstract_adapter.rb +30 -9
  21. data/lib/cancan/model_adapters/active_record_4_adapter.rb +43 -15
  22. data/lib/cancan/model_adapters/active_record_5_adapter.rb +61 -0
  23. data/lib/cancan/model_adapters/active_record_adapter.rb +157 -82
  24. data/lib/cancan/model_adapters/conditions_extractor.rb +75 -0
  25. data/lib/cancan/model_adapters/conditions_normalizer.rb +49 -0
  26. data/lib/cancan/model_adapters/default_adapter.rb +2 -0
  27. data/lib/cancan/model_adapters/sti_normalizer.rb +47 -0
  28. data/lib/cancan/model_adapters/strategies/base.rb +40 -0
  29. data/lib/cancan/model_adapters/strategies/joined_alias_each_rule_as_exists_subquery.rb +93 -0
  30. data/lib/cancan/model_adapters/strategies/joined_alias_exists_subquery.rb +31 -0
  31. data/lib/cancan/model_adapters/strategies/left_join.rb +11 -0
  32. data/lib/cancan/model_adapters/strategies/subquery.rb +18 -0
  33. data/lib/cancan/model_additions.rb +6 -3
  34. data/lib/cancan/parameter_validators.rb +9 -0
  35. data/lib/cancan/relevant.rb +29 -0
  36. data/lib/cancan/rule.rb +79 -91
  37. data/lib/cancan/rules_compressor.rb +23 -0
  38. data/lib/cancan/sti_detector.rb +12 -0
  39. data/lib/cancan/unauthorized_message_resolver.rb +24 -0
  40. data/lib/cancan/version.rb +3 -1
  41. data/lib/cancan.rb +16 -12
  42. data/lib/cancancan.rb +2 -0
  43. data/lib/generators/cancan/ability/ability_generator.rb +4 -2
  44. data/lib/generators/cancan/ability/templates/ability.rb +9 -9
  45. metadata +82 -93
  46. data/.gitignore +0 -15
  47. data/.rspec +0 -1
  48. data/.travis.yml +0 -48
  49. data/Appraisals +0 -135
  50. data/CHANGELOG.rdoc +0 -495
  51. data/CONTRIBUTING.md +0 -23
  52. data/Gemfile +0 -3
  53. data/LICENSE +0 -22
  54. data/README.md +0 -197
  55. data/Rakefile +0 -9
  56. data/gemfiles/activerecord_3.0.gemfile +0 -18
  57. data/gemfiles/activerecord_3.1.gemfile +0 -20
  58. data/gemfiles/activerecord_3.2.gemfile +0 -20
  59. data/gemfiles/activerecord_4.0.gemfile +0 -17
  60. data/gemfiles/activerecord_4.1.gemfile +0 -17
  61. data/gemfiles/activerecord_4.2.gemfile +0 -17
  62. data/gemfiles/datamapper_1.x.gemfile +0 -14
  63. data/gemfiles/mongoid_2.x.gemfile +0 -20
  64. data/gemfiles/sequel_3.x.gemfile +0 -20
  65. data/lib/cancan/inherited_resource.rb +0 -20
  66. data/lib/cancan/model_adapters/active_record_3_adapter.rb +0 -47
  67. data/lib/cancan/model_adapters/data_mapper_adapter.rb +0 -34
  68. data/lib/cancan/model_adapters/mongoid_adapter.rb +0 -54
  69. data/lib/cancan/model_adapters/sequel_adapter.rb +0 -87
  70. data/spec/README.rdoc +0 -27
  71. data/spec/cancan/ability_spec.rb +0 -487
  72. data/spec/cancan/controller_additions_spec.rb +0 -141
  73. data/spec/cancan/controller_resource_spec.rb +0 -648
  74. data/spec/cancan/exceptions_spec.rb +0 -58
  75. data/spec/cancan/inherited_resource_spec.rb +0 -71
  76. data/spec/cancan/matchers_spec.rb +0 -29
  77. data/spec/cancan/model_adapters/active_record_4_adapter_spec.rb +0 -40
  78. data/spec/cancan/model_adapters/active_record_adapter_spec.rb +0 -446
  79. data/spec/cancan/model_adapters/data_mapper_adapter_spec.rb +0 -119
  80. data/spec/cancan/model_adapters/default_adapter_spec.rb +0 -7
  81. data/spec/cancan/model_adapters/mongoid_adapter_spec.rb +0 -227
  82. data/spec/cancan/model_adapters/sequel_adapter_spec.rb +0 -132
  83. data/spec/cancan/rule_spec.rb +0 -52
  84. data/spec/matchers.rb +0 -13
  85. data/spec/spec.opts +0 -2
  86. data/spec/spec_helper.rb +0 -27
  87. data/spec/support/ability.rb +0 -7
@@ -1,648 +0,0 @@
1
- require "spec_helper"
2
-
3
- describe CanCan::ControllerResource do
4
- let(:ability) { Ability.new(nil) }
5
- let(:params) { HashWithIndifferentAccess.new(:controller => "models") }
6
- let(:controller_class) { Class.new }
7
- let(:controller) { controller_class.new }
8
-
9
- before(:each) do
10
- class Model
11
- attr_accessor :name
12
-
13
- def initialize(attributes={})
14
- attributes.each do |attribute, value|
15
- send("#{attribute}=", value)
16
- end
17
- end
18
- end
19
-
20
- allow(controller).to receive(:params) { params }
21
- allow(controller).to receive(:current_ability) { ability }
22
- allow(controller_class).to receive(:cancan_skipper) { {:authorize => {}, :load => {}} }
23
- end
24
-
25
- context "on build actions" do
26
- before :each do
27
- params.merge!(:action => "new")
28
- end
29
-
30
- it "builds a new resource with attributes from current ability" do
31
- ability.can(:create, Model, :name => "from conditions")
32
- resource = CanCan::ControllerResource.new(controller)
33
- resource.load_resource
34
- expect(controller.instance_variable_get(:@model).name).to eq("from conditions")
35
- end
36
-
37
- it "overrides initial attributes with params" do
38
- params.merge!(:model => {:name => "from params"})
39
- ability.can(:create, Model, :name => "from conditions")
40
- resource = CanCan::ControllerResource.new(controller)
41
- resource.load_resource
42
- expect(controller.instance_variable_get(:@model).name).to eq("from params")
43
- end
44
-
45
- it "builds a resource when on custom new action even when params[:id] exists" do
46
- params.merge!(:action => "build", :id => "123")
47
- allow(Model).to receive(:new) { :some_model }
48
- resource = CanCan::ControllerResource.new(controller, :new => :build)
49
- resource.load_resource
50
- expect(controller.instance_variable_get(:@model)).to eq(:some_model)
51
- end
52
-
53
- it "only authorizes :show action on parent resource" do
54
- model = Model.new
55
- allow(Model).to receive(:find).with("123") { model }
56
-
57
- params.merge!(:model_id => 123)
58
- allow(controller).to receive(:authorize!).with(:show, model) { raise CanCan::AccessDenied }
59
- resource = CanCan::ControllerResource.new(controller, :model, :parent => true)
60
- expect { resource.load_and_authorize_resource }.to raise_error(CanCan::AccessDenied)
61
- end
62
- end
63
-
64
- context "on create actions" do
65
- before :each do
66
- params.merge!(:action => 'create')
67
- end
68
-
69
- # Rails includes namespace in params, see issue #349
70
- it "creates through the namespaced params" do
71
- module MyEngine
72
- class Model < ::Model; end
73
- end
74
-
75
- params.merge!(:controller => "MyEngine::ModelsController", :my_engine_model => {:name => "foobar"})
76
- resource = CanCan::ControllerResource.new(controller)
77
- resource.load_resource
78
- expect(controller.instance_variable_get(:@model).name).to eq("foobar")
79
- end
80
-
81
- it "builds a new resource with hash if params[:id] is not specified" do
82
- params.merge!(:model => {:name => "foobar"})
83
- resource = CanCan::ControllerResource.new(controller)
84
- resource.load_resource
85
- expect(controller.instance_variable_get(:@model).name).to eq("foobar")
86
- end
87
-
88
- it "builds a new resource for namespaced model with hash if params[:id] is not specified" do
89
- module Sub
90
- class Model < ::Model; end
91
- end
92
-
93
- params.merge!('sub_model' => {:name => "foobar"})
94
- resource = CanCan::ControllerResource.new(controller, :class => ::Sub::Model)
95
- resource.load_resource
96
- expect(controller.instance_variable_get(:@model).name).to eq("foobar")
97
- end
98
-
99
- it "builds a new resource for namespaced controller and namespaced model with hash if params[:id] is not specified" do
100
- params.merge!(:controller => "Admin::SubModelsController", 'sub_model' => {:name => "foobar"})
101
- resource = CanCan::ControllerResource.new(controller, :class => Model)
102
- resource.load_resource
103
- expect(controller.instance_variable_get(:@sub_model).name).to eq("foobar")
104
- end
105
-
106
- it "builds a new resource for namespaced controller given through folder format" do
107
- module Admin
108
- module SubModule
109
- class HiddenModel < ::Model; end
110
- end
111
- end
112
- params.merge!(:controller => "admin/sub_module/hidden_models")
113
- resource = CanCan::ControllerResource.new(controller)
114
- expect { resource.load_resource }.not_to raise_error
115
- end
116
-
117
- it "does not build record through has_one association with :singleton option because it can cause it to delete it in the database" do
118
- category = Class.new
119
- allow_any_instance_of(Model).to receive('category=').with(category)
120
- allow_any_instance_of(Model).to receive('category') { category }
121
-
122
- params.merge!(:model => {:name => "foobar"})
123
-
124
- controller.instance_variable_set(:@category, category)
125
- resource = CanCan::ControllerResource.new(controller, :through => :category, :singleton => true)
126
- resource.load_resource
127
- expect(controller.instance_variable_get(:@model).name).to eq("foobar")
128
- expect(controller.instance_variable_get(:@model).category).to eq(category)
129
- end
130
-
131
- it "builds record through has_one association with :singleton and :shallow options" do
132
- params.merge!(:model => {:name => "foobar"})
133
- resource = CanCan::ControllerResource.new(controller, :through => :category, :singleton => true, :shallow => true)
134
- resource.load_resource
135
- expect(controller.instance_variable_get(:@model).name).to eq("foobar")
136
- end
137
-
138
- context "with a strong parameters method" do
139
- before :each do
140
- params.merge!(:controller => "model", :model => { :name => 'test'})
141
- end
142
-
143
- it "accepts and uses the specified symbol for santitizing input" do
144
- allow(controller).to receive(:resource_params).and_return(:resource => 'params')
145
- allow(controller).to receive(:model_params).and_return(:model => 'params')
146
- allow(controller).to receive(:create_params).and_return(:create => 'params')
147
- allow(controller).to receive(:custom_params).and_return(:custom => 'params')
148
- resource = CanCan::ControllerResource.new(controller, {:param_method => :custom_params})
149
- expect(resource.send("resource_params")).to eq(:custom => 'params')
150
- end
151
-
152
- it "accepts the specified string for sanitizing input" do
153
- resource = CanCan::ControllerResource.new(controller, {:param_method => "{:custom => 'params'}"})
154
- expect(resource.send("resource_params")).to eq(:custom => 'params')
155
- end
156
-
157
- it "accepts the specified proc for sanitizing input" do
158
- resource = CanCan::ControllerResource.new(controller, {:param_method => Proc.new { |c| {:custom => 'params'}}})
159
- expect(resource.send("resource_params")).to eq(:custom => 'params')
160
- end
161
-
162
- it "prefers to use the create_params method for santitizing input" do
163
- allow(controller).to receive(:resource_params).and_return(:resource => 'params')
164
- allow(controller).to receive(:model_params).and_return(:model => 'params')
165
- allow(controller).to receive(:create_params).and_return(:create => 'params')
166
- allow(controller).to receive(:custom_params).and_return(:custom => 'params')
167
- resource = CanCan::ControllerResource.new(controller)
168
- expect(resource.send("resource_params")).to eq(:create => 'params')
169
- end
170
-
171
- it "prefers to use the <model_name>_params method for santitizing input if create is not found" do
172
- allow(controller).to receive(:resource_params).and_return(:resource => 'params')
173
- allow(controller).to receive(:model_params).and_return(:model => 'params')
174
- allow(controller).to receive(:custom_params).and_return(:custom => 'params')
175
- resource = CanCan::ControllerResource.new(controller)
176
- expect(resource.send("resource_params")).to eq(:model => 'params')
177
- end
178
-
179
- it "prefers to use the resource_params method for santitizing input if create or model is not found" do
180
- allow(controller).to receive(:resource_params).and_return(:resource => 'params')
181
- allow(controller).to receive(:custom_params).and_return(:custom => 'params')
182
- resource = CanCan::ControllerResource.new(controller)
183
- expect(resource.send("resource_params")).to eq(:resource => 'params')
184
- end
185
- end
186
- end
187
-
188
- context "on collection actions" do
189
- before :each do
190
- params[:action] = 'index'
191
- end
192
-
193
- it "builds a collection when on index action when class responds to accessible_by" do
194
- allow(Model).to receive(:accessible_by).with(ability, :index) { :found_models }
195
-
196
- resource = CanCan::ControllerResource.new(controller, :model)
197
- resource.load_resource
198
- expect(controller.instance_variable_get(:@model)).to be_nil
199
- expect(controller.instance_variable_get(:@models)).to eq(:found_models)
200
- end
201
-
202
- it "does not build a collection when on index action when class does not respond to accessible_by" do
203
- resource = CanCan::ControllerResource.new(controller)
204
- resource.load_resource
205
- expect(controller.instance_variable_get(:@model)).to be_nil
206
- expect(controller.instance_variable_defined?(:@models)).to be(false)
207
- end
208
-
209
- it "does not use accessible_by when defining abilities through a block" do
210
- allow(Model).to receive(:accessible_by).with(ability) { :found_models }
211
-
212
- ability.can(:read, Model) { |p| false }
213
- resource = CanCan::ControllerResource.new(controller)
214
- resource.load_resource
215
- expect(controller.instance_variable_get(:@model)).to be_nil
216
- expect(controller.instance_variable_defined?(:@models)).to be(false)
217
- end
218
-
219
- it "does not authorize single resource in collection action" do
220
- allow(controller).to receive(:authorize!).with(:index, Model) { raise CanCan::AccessDenied }
221
- resource = CanCan::ControllerResource.new(controller)
222
-
223
- expect { resource.authorize_resource }.to raise_error(CanCan::AccessDenied)
224
- end
225
-
226
- it "authorizes parent resource in collection action" do
227
- controller.instance_variable_set(:@category, :some_category)
228
- allow(controller).to receive(:authorize!).with(:show, :some_category) { raise CanCan::AccessDenied }
229
-
230
- resource = CanCan::ControllerResource.new(controller, :category, :parent => true)
231
- expect { resource.authorize_resource }.to raise_error(CanCan::AccessDenied)
232
- end
233
-
234
- it "has the specified nested resource_class when using / for namespace" do
235
- module Admin
236
- class Dashboard; end
237
- end
238
- ability.can(:index, "admin/dashboard")
239
- params.merge!(:controller => "admin/dashboard")
240
- resource = CanCan::ControllerResource.new(controller, :authorize => true)
241
- expect(resource.send(:resource_class)).to eq(Admin::Dashboard)
242
- end
243
-
244
- it "does not build a single resource when on custom collection action even with id" do
245
- params.merge!(:action => "sort", :id => "123")
246
-
247
- resource = CanCan::ControllerResource.new(controller, :collection => [:sort, :list])
248
- resource.load_resource
249
- expect(controller.instance_variable_get(:@model)).to be_nil
250
- end
251
-
252
- it "loads a collection resource when on custom action with no id param" do
253
- allow(Model).to receive(:accessible_by).with(ability, :sort) { :found_models }
254
- params[:action] = "sort"
255
- resource = CanCan::ControllerResource.new(controller)
256
- resource.load_resource
257
- expect(controller.instance_variable_get(:@model)).to be_nil
258
- expect(controller.instance_variable_get(:@models)).to eq(:found_models)
259
- end
260
-
261
- it "loads parent resource through proper id parameter" do
262
- model = Model.new
263
- allow(Model).to receive(:find).with("1") { model }
264
-
265
- params.merge!(:controller => "categories", :model_id => 1)
266
- resource = CanCan::ControllerResource.new(controller, :model)
267
- resource.load_resource
268
- expect(controller.instance_variable_get(:@model)).to eq(model)
269
- end
270
-
271
- it "authorizes nested resource through parent association on index action" do
272
- controller.instance_variable_set(:@category, category = double)
273
- allow(controller).to receive(:authorize!).with(:index, category => Model) { raise CanCan::AccessDenied }
274
- resource = CanCan::ControllerResource.new(controller, :through => :category)
275
- expect { resource.authorize_resource }.to raise_error(CanCan::AccessDenied)
276
- end
277
- end
278
-
279
- context "on instance read actions" do
280
- before :each do
281
- params.merge!(:action => "show", :id => "123")
282
- end
283
-
284
- it "loads the resource into an instance variable if params[:id] is specified" do
285
- model = Model.new
286
- allow(Model).to receive(:find).with("123") { model }
287
-
288
- resource = CanCan::ControllerResource.new(controller)
289
- resource.load_resource
290
- expect(controller.instance_variable_get(:@model)).to eq(model)
291
- end
292
-
293
- it "does not load resource into an instance variable if already set" do
294
- controller.instance_variable_set(:@model, :some_model)
295
- resource = CanCan::ControllerResource.new(controller)
296
- resource.load_resource
297
- expect(controller.instance_variable_get(:@model)).to eq(:some_model)
298
- end
299
-
300
- it "loads resource for namespaced controller" do
301
- model = Model.new
302
- allow(Model).to receive(:find).with("123") { model }
303
- params.merge!(:controller => "admin/models")
304
-
305
- resource = CanCan::ControllerResource.new(controller)
306
- resource.load_resource
307
- expect(controller.instance_variable_get(:@model)).to eq(model)
308
- end
309
-
310
- it "attempts to load a resource with the same namespace as the controller when using :: for namespace" do
311
- module MyEngine
312
- class Model < ::Model; end
313
- end
314
-
315
- model = MyEngine::Model.new
316
- allow(MyEngine::Model).to receive(:find).with("123") { model }
317
-
318
- params.merge!(:controller => "MyEngine::ModelsController")
319
- resource = CanCan::ControllerResource.new(controller)
320
- resource.load_resource
321
- expect(controller.instance_variable_get(:@model)).to eq(model)
322
- end
323
-
324
- it "loads resource for namespaced controller when using '::' for namespace" do
325
- model = Model.new
326
- allow(Model).to receive(:find).with("123") { model }
327
-
328
- params.merge!(:controller => "Admin::ModelsController")
329
- resource = CanCan::ControllerResource.new(controller)
330
- resource.load_resource
331
- expect(controller.instance_variable_get(:@model)).to eq(model)
332
- end
333
-
334
- it "performs authorization using controller action and loaded model" do
335
- controller.instance_variable_set(:@model, :some_model)
336
- allow(controller).to receive(:authorize!).with(:show, :some_model) { raise CanCan::AccessDenied }
337
-
338
- resource = CanCan::ControllerResource.new(controller)
339
- expect { resource.authorize_resource }.to raise_error(CanCan::AccessDenied)
340
- end
341
-
342
- it "performs authorization using controller action and non loaded model" do
343
- allow(controller).to receive(:authorize!).with(:show, Model) { raise CanCan::AccessDenied }
344
- resource = CanCan::ControllerResource.new(controller)
345
- expect { resource.authorize_resource }.to raise_error(CanCan::AccessDenied)
346
- end
347
-
348
- it "calls load_resource and authorize_resource for load_and_authorize_resource" do
349
- resource = CanCan::ControllerResource.new(controller)
350
- expect(resource).to receive(:load_resource)
351
- expect(resource).to receive(:authorize_resource)
352
- resource.load_and_authorize_resource
353
- end
354
-
355
- it "loads resource through the association of another parent resource using instance variable" do
356
- category = double(:models => {})
357
- controller.instance_variable_set(:@category, category)
358
- allow(category.models).to receive(:find).with("123") { :some_model }
359
- resource = CanCan::ControllerResource.new(controller, :through => :category)
360
- resource.load_resource
361
- expect(controller.instance_variable_get(:@model)).to eq(:some_model)
362
- end
363
-
364
- it "loads resource through the custom association name" do
365
- category = double(:custom_models => {})
366
- controller.instance_variable_set(:@category, category)
367
- allow(category.custom_models).to receive(:find).with("123") { :some_model }
368
- resource = CanCan::ControllerResource.new(controller, :through => :category, :through_association => :custom_models)
369
- resource.load_resource
370
- expect(controller.instance_variable_get(:@model)).to eq(:some_model)
371
- end
372
-
373
- it "loads resource through the association of another parent resource using method" do
374
- category = double(:models => {})
375
- allow(controller).to receive(:category) { category }
376
- allow(category.models).to receive(:find).with("123") { :some_model }
377
- resource = CanCan::ControllerResource.new(controller, :through => :category)
378
- resource.load_resource
379
- expect(controller.instance_variable_get(:@model)).to eq(:some_model)
380
- end
381
-
382
- it "does not load through parent resource if instance isn't loaded when shallow" do
383
- model = Model.new
384
- allow(Model).to receive(:find).with("123") { model }
385
-
386
- resource = CanCan::ControllerResource.new(controller, :through => :category, :shallow => true)
387
- resource.load_resource
388
- expect(controller.instance_variable_get(:@model)).to eq(model)
389
- end
390
-
391
- it "raises AccessDenied when attempting to load resource through nil" do
392
- resource = CanCan::ControllerResource.new(controller, :through => :category)
393
- expect {
394
- resource.load_resource
395
- }.to raise_error(CanCan::AccessDenied) { |exception|
396
- expect(exception.action).to eq(:show)
397
- expect(exception.subject).to eq(Model)
398
- }
399
- expect(controller.instance_variable_get(:@model)).to be_nil
400
- end
401
-
402
- it "loads through first matching if multiple are given" do
403
- category = double(:models => {})
404
- controller.instance_variable_set(:@category, category)
405
- allow(category.models).to receive(:find).with("123") { :some_model }
406
-
407
- resource = CanCan::ControllerResource.new(controller, :through => [:category, :user])
408
- resource.load_resource
409
- expect(controller.instance_variable_get(:@model)).to eq(:some_model)
410
- end
411
-
412
- it "finds record through has_one association with :singleton option without id param" do
413
- params.merge!(:id => nil)
414
-
415
- category = double(:model => :some_model)
416
- controller.instance_variable_set(:@category, category)
417
- resource = CanCan::ControllerResource.new(controller, :through => :category, :singleton => true)
418
- resource.load_resource
419
- expect(controller.instance_variable_get(:@model)).to eq(:some_model)
420
- end
421
-
422
- it "does not try to load resource for other action if params[:id] is undefined" do
423
- params.merge!(:action => 'list', :id => nil)
424
- resource = CanCan::ControllerResource.new(controller)
425
- resource.load_resource
426
- expect(controller.instance_variable_get(:@model)).to be_nil
427
- end
428
-
429
- it "finds record through has_one association with :singleton and :shallow options" do
430
- model = Model.new
431
- allow(Model).to receive(:find).with("123") { model }
432
-
433
- resource = CanCan::ControllerResource.new(controller, :through => :category, :singleton => true, :shallow => true)
434
- resource.load_resource
435
- expect(controller.instance_variable_get(:@model)).to eq(model)
436
- end
437
-
438
- it "loads the model using a custom class" do
439
- model = Model.new
440
- allow(Model).to receive(:find).with("123") { model }
441
-
442
- resource = CanCan::ControllerResource.new(controller, :class => Model)
443
- resource.load_resource
444
- expect(controller.instance_variable_get(:@model)).to eq(model)
445
- end
446
-
447
- it "loads the model using a custom namespaced class" do
448
- module Sub
449
- class Model < ::Model; end
450
- end
451
-
452
- model = Sub::Model.new
453
- allow(Sub::Model).to receive(:find).with("123") { model }
454
-
455
- resource = CanCan::ControllerResource.new(controller, :class => ::Sub::Model)
456
- resource.load_resource
457
- expect(controller.instance_variable_get(:@model)).to eq(model)
458
- end
459
-
460
- it "authorizes based on resource name if class is false" do
461
- allow(controller).to receive(:authorize!).with(:show, :model) { raise CanCan::AccessDenied }
462
- resource = CanCan::ControllerResource.new(controller, :class => false)
463
- expect { resource.authorize_resource }.to raise_error(CanCan::AccessDenied)
464
- end
465
-
466
- it "loads and authorize using custom instance name" do
467
- model = Model.new
468
- allow(Model).to receive(:find).with("123") { model }
469
-
470
- allow(controller).to receive(:authorize!).with(:show, model) { raise CanCan::AccessDenied }
471
- resource = CanCan::ControllerResource.new(controller, :instance_name => :custom_model)
472
- expect { resource.load_and_authorize_resource }.to raise_error(CanCan::AccessDenied)
473
- expect(controller.instance_variable_get(:@custom_model)).to eq(model)
474
- end
475
-
476
- it "loads resource using custom ID param" do
477
- model = Model.new
478
- allow(Model).to receive(:find).with("123") { model }
479
-
480
- params.merge!(:the_model => 123)
481
- resource = CanCan::ControllerResource.new(controller, :id_param => :the_model)
482
- resource.load_resource
483
- expect(controller.instance_variable_get(:@model)).to eq(model)
484
- end
485
-
486
- # CVE-2012-5664
487
- it "always converts id param to string" do
488
- params.merge!(:the_model => { :malicious => "I am" })
489
- resource = CanCan::ControllerResource.new(controller, :id_param => :the_model)
490
- expect(resource.send(:id_param).class).to eq(String)
491
- end
492
-
493
- it "should id param return nil if param is nil" do
494
- params.merge!(:the_model => nil)
495
- resource = CanCan::ControllerResource.new(controller, :id_param => :the_model)
496
- expect(resource.send(:id_param)).to be_nil
497
- end
498
-
499
- it "loads resource using custom find_by attribute" do
500
- model = Model.new
501
- allow(Model).to receive(:name).with('foo') { model }
502
-
503
- params.merge!(:action => "show", :id => "foo")
504
- resource = CanCan::ControllerResource.new(controller, :find_by => :name)
505
- resource.load_resource
506
- expect(controller.instance_variable_get(:@model)).to eq(model)
507
- end
508
-
509
- it "allows full find method to be passed into find_by option" do
510
- model = Model.new
511
- allow(Model).to receive(:find_by_name).with('foo') { model }
512
-
513
- params.merge!(:action => "show", :id => "foo")
514
- resource = CanCan::ControllerResource.new(controller, :find_by => :find_by_name)
515
- resource.load_resource
516
- expect(controller.instance_variable_get(:@model)).to eq(model)
517
- end
518
- end
519
-
520
- it "calls the santitizer when the parameter hash matches our object" do
521
- params.merge!(:action => 'create', :model => { :name => 'test' })
522
- allow(controller).to receive(:create_params).and_return({})
523
-
524
- resource = CanCan::ControllerResource.new(controller)
525
- resource.load_resource
526
- expect(controller.instance_variable_get(:@model).name).to eq nil
527
- end
528
-
529
- it "santitizes correctly when the instance name is overriden" do
530
- params.merge!(:action => 'create', :custom_name => {:name => "foobar"})
531
- allow(controller).to receive(:create_params).and_return({})
532
-
533
- resource = CanCan::ControllerResource.new(controller, :instance_name => :custom_name)
534
- resource.load_resource
535
- expect(controller.instance_variable_get(:@custom_name).name).to eq nil
536
- end
537
-
538
- it "calls the santitize method on non-save actions when required" do
539
- params.merge!(:action => 'new', :model => { :name => 'test' })
540
-
541
- allow(controller).to receive(:resource_params).and_return({})
542
- resource = CanCan::ControllerResource.new(controller)
543
- resource.load_resource
544
- expect(controller.instance_variable_get(:@model).name).to eq nil
545
- end
546
-
547
- it "doesn't sanitize parameters on non-save actions when not required" do
548
- params.merge!(:action => 'new', :not_our_model => { :name => 'test' })
549
- allow(controller).to receive(:resource_params).and_raise
550
-
551
- resource = CanCan::ControllerResource.new(controller)
552
- expect {
553
- resource.load_resource
554
- }.to_not raise_error
555
- end
556
-
557
- it "is a parent resource when name is provided which doesn't match controller" do
558
- resource = CanCan::ControllerResource.new(controller, :category)
559
- expect(resource).to be_parent
560
- end
561
-
562
- it "does not be a parent resource when name is provided which matches controller" do
563
- resource = CanCan::ControllerResource.new(controller, :model)
564
- expect(resource).to_not be_parent
565
- end
566
-
567
- it "is parent if specified in options" do
568
- resource = CanCan::ControllerResource.new(controller, :model, {:parent => true})
569
- expect(resource).to be_parent
570
- end
571
-
572
- it "does not be parent if specified in options" do
573
- resource = CanCan::ControllerResource.new(controller, :category, {:parent => false})
574
- expect(resource).to_not be_parent
575
- end
576
-
577
- it "has the specified resource_class if 'name' is passed to load_resource" do
578
- class Section; end
579
- resource = CanCan::ControllerResource.new(controller, :section)
580
- expect(resource.send(:resource_class)).to eq(Section)
581
- end
582
-
583
- it "raises ImplementationRemoved when adding :name option" do
584
- expect {
585
- CanCan::ControllerResource.new(controller, :name => :foo)
586
- }.to raise_error(CanCan::ImplementationRemoved)
587
- end
588
-
589
- it "raises ImplementationRemoved exception when specifying :resource option since it is no longer used" do
590
- expect {
591
- CanCan::ControllerResource.new(controller, :resource => Model)
592
- }.to raise_error(CanCan::ImplementationRemoved)
593
- end
594
-
595
- it "raises ImplementationRemoved exception when passing :nested option" do
596
- expect {
597
- CanCan::ControllerResource.new(controller, :nested => :model)
598
- }.to raise_error(CanCan::ImplementationRemoved)
599
- end
600
-
601
- it "skips resource behavior for :only actions in array" do
602
- allow(controller_class).to receive(:cancan_skipper) { {:load => {nil => {:only => [:index, :show]}}} }
603
- params.merge!(:action => "index")
604
- expect(CanCan::ControllerResource.new(controller).skip?(:load)).to be(true)
605
- expect(CanCan::ControllerResource.new(controller, :some_resource).skip?(:load)).to be(false)
606
- params.merge!(:action => "show")
607
- expect(CanCan::ControllerResource.new(controller).skip?(:load)).to be(true)
608
- params.merge!(:action => "other_action")
609
- expect(CanCan::ControllerResource.new(controller).skip?(:load)).to be_falsey
610
- end
611
-
612
- it "skips resource behavior for :only one action on resource" do
613
- allow(controller_class).to receive(:cancan_skipper) { {:authorize => {:model => {:only => :index}}} }
614
- params.merge!(:action => "index")
615
- expect(CanCan::ControllerResource.new(controller).skip?(:authorize)).to be(false)
616
- expect(CanCan::ControllerResource.new(controller, :model).skip?(:authorize)).to be(true)
617
- params.merge!(:action => "other_action")
618
- expect(CanCan::ControllerResource.new(controller, :model).skip?(:authorize)).to be_falsey
619
- end
620
-
621
- it "skips resource behavior :except actions in array" do
622
- allow(controller_class).to receive(:cancan_skipper) { {:load => {nil => {:except => [:index, :show]}}} }
623
- params.merge!(:action => "index")
624
- expect(CanCan::ControllerResource.new(controller).skip?(:load)).to be_falsey
625
- params.merge!(:action => "show")
626
- expect(CanCan::ControllerResource.new(controller).skip?(:load)).to be_falsey
627
- params.merge!(:action => "other_action")
628
- expect(CanCan::ControllerResource.new(controller).skip?(:load)).to be(true)
629
- expect(CanCan::ControllerResource.new(controller, :some_resource).skip?(:load)).to be(false)
630
- end
631
-
632
- it "skips resource behavior :except one action on resource" do
633
- allow(controller_class).to receive(:cancan_skipper) { {:authorize => {:model => {:except => :index}}} }
634
- params.merge!(:action => "index")
635
- expect(CanCan::ControllerResource.new(controller, :model).skip?(:authorize)).to be_falsey
636
- params.merge!(:action => "other_action")
637
- expect(CanCan::ControllerResource.new(controller).skip?(:authorize)).to be(false)
638
- expect(CanCan::ControllerResource.new(controller, :model).skip?(:authorize)).to be(true)
639
- end
640
-
641
- it "skips loading and authorization" do
642
- allow(controller_class).to receive(:cancan_skipper) { {:authorize => {nil => {}}, :load => {nil => {}}} }
643
- params.merge!(:action => "new")
644
- resource = CanCan::ControllerResource.new(controller)
645
- expect { resource.load_and_authorize_resource }.not_to raise_error
646
- expect(controller.instance_variable_get(:@model)).to be_nil
647
- end
648
- end