cancancan 1.17.0 → 3.5.0

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