cancancan 1.13.1 → 3.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +5 -5
  2. data/cancancan.gemspec +18 -18
  3. data/init.rb +2 -0
  4. data/lib/cancan.rb +9 -11
  5. data/lib/cancan/ability.rb +93 -194
  6. data/lib/cancan/ability/actions.rb +93 -0
  7. data/lib/cancan/ability/rules.rb +93 -0
  8. data/lib/cancan/ability/strong_parameter_support.rb +41 -0
  9. data/lib/cancan/conditions_matcher.rb +106 -0
  10. data/lib/cancan/controller_additions.rb +38 -41
  11. data/lib/cancan/controller_resource.rb +52 -211
  12. data/lib/cancan/controller_resource_builder.rb +26 -0
  13. data/lib/cancan/controller_resource_finder.rb +42 -0
  14. data/lib/cancan/controller_resource_loader.rb +120 -0
  15. data/lib/cancan/controller_resource_name_finder.rb +23 -0
  16. data/lib/cancan/controller_resource_sanitizer.rb +32 -0
  17. data/lib/cancan/exceptions.rb +17 -5
  18. data/lib/cancan/matchers.rb +12 -3
  19. data/lib/cancan/model_adapters/abstract_adapter.rb +10 -8
  20. data/lib/cancan/model_adapters/active_record_4_adapter.rb +39 -13
  21. data/lib/cancan/model_adapters/active_record_5_adapter.rb +68 -0
  22. data/lib/cancan/model_adapters/active_record_adapter.rb +77 -82
  23. data/lib/cancan/model_adapters/conditions_extractor.rb +75 -0
  24. data/lib/cancan/model_adapters/conditions_normalizer.rb +49 -0
  25. data/lib/cancan/model_adapters/default_adapter.rb +2 -0
  26. data/lib/cancan/model_additions.rb +2 -1
  27. data/lib/cancan/parameter_validators.rb +9 -0
  28. data/lib/cancan/relevant.rb +29 -0
  29. data/lib/cancan/rule.rb +76 -105
  30. data/lib/cancan/rules_compressor.rb +23 -0
  31. data/lib/cancan/unauthorized_message_resolver.rb +24 -0
  32. data/lib/cancan/version.rb +3 -1
  33. data/lib/cancancan.rb +2 -0
  34. data/lib/generators/cancan/ability/ability_generator.rb +4 -2
  35. data/lib/generators/cancan/ability/templates/ability.rb +2 -0
  36. metadata +66 -56
  37. data/.gitignore +0 -15
  38. data/.rspec +0 -1
  39. data/.travis.yml +0 -28
  40. data/Appraisals +0 -81
  41. data/CHANGELOG.rdoc +0 -518
  42. data/CONTRIBUTING.md +0 -23
  43. data/Gemfile +0 -3
  44. data/LICENSE +0 -22
  45. data/README.md +0 -214
  46. data/Rakefile +0 -9
  47. data/gemfiles/activerecord_3.2.gemfile +0 -16
  48. data/gemfiles/activerecord_4.0.gemfile +0 -17
  49. data/gemfiles/activerecord_4.1.gemfile +0 -17
  50. data/gemfiles/activerecord_4.2.gemfile +0 -18
  51. data/gemfiles/mongoid_2.x.gemfile +0 -16
  52. data/gemfiles/sequel_3.x.gemfile +0 -16
  53. data/lib/cancan/inherited_resource.rb +0 -20
  54. data/lib/cancan/model_adapters/active_record_3_adapter.rb +0 -16
  55. data/lib/cancan/model_adapters/mongoid_adapter.rb +0 -54
  56. data/lib/cancan/model_adapters/sequel_adapter.rb +0 -87
  57. data/spec/README.rdoc +0 -27
  58. data/spec/cancan/ability_spec.rb +0 -521
  59. data/spec/cancan/controller_additions_spec.rb +0 -141
  60. data/spec/cancan/controller_resource_spec.rb +0 -632
  61. data/spec/cancan/exceptions_spec.rb +0 -58
  62. data/spec/cancan/inherited_resource_spec.rb +0 -71
  63. data/spec/cancan/matchers_spec.rb +0 -29
  64. data/spec/cancan/model_adapters/active_record_4_adapter_spec.rb +0 -85
  65. data/spec/cancan/model_adapters/active_record_adapter_spec.rb +0 -384
  66. data/spec/cancan/model_adapters/default_adapter_spec.rb +0 -7
  67. data/spec/cancan/model_adapters/mongoid_adapter_spec.rb +0 -227
  68. data/spec/cancan/model_adapters/sequel_adapter_spec.rb +0 -132
  69. data/spec/cancan/rule_spec.rb +0 -52
  70. data/spec/matchers.rb +0 -13
  71. data/spec/spec.opts +0 -2
  72. data/spec/spec_helper.rb +0 -27
  73. data/spec/support/ability.rb +0 -7
@@ -1,141 +0,0 @@
1
- require "spec_helper"
2
-
3
- describe CanCan::ControllerAdditions do
4
- before(:each) do
5
- @controller_class = Class.new
6
- @controller = @controller_class.new
7
- allow(@controller).to receive(:params) { {} }
8
- allow(@controller).to receive(:current_user) { :current_user }
9
- expect(@controller_class).to receive(:helper_method).with(:can?, :cannot?, :current_ability)
10
- @controller_class.send(:include, CanCan::ControllerAdditions)
11
- end
12
-
13
- it "raises ImplementationRemoved when attempting to call 'unauthorized!' on a controller" do
14
- expect { @controller.unauthorized! }.to raise_error(CanCan::ImplementationRemoved)
15
- end
16
-
17
- it "authorize! assigns @_authorized instance variable and pass args to current ability" do
18
- allow(@controller.current_ability).to receive(:authorize!).with(:foo, :bar)
19
- @controller.authorize!(:foo, :bar)
20
- expect(@controller.instance_variable_get(:@_authorized)).to be(true)
21
- end
22
-
23
- it "has a current_ability method which generates an ability for the current user" do
24
- expect(@controller.current_ability).to be_kind_of(Ability)
25
- end
26
-
27
- it "provides a can? and cannot? methods which go through the current ability" do
28
- expect(@controller.current_ability).to be_kind_of(Ability)
29
- expect(@controller.can?(:foo, :bar)).to be(false)
30
- expect(@controller.cannot?(:foo, :bar)).to be(true)
31
- end
32
-
33
- it "load_and_authorize_resource setups a before filter which passes call to ControllerResource" do
34
- expect(cancan_resource_class = double).to receive(:load_and_authorize_resource)
35
- allow(CanCan::ControllerResource).to receive(:new).with(@controller, nil, :foo => :bar) {cancan_resource_class }
36
- expect(@controller_class).to receive(:before_filter).with({}) { |options, &block| block.call(@controller) }
37
- @controller_class.load_and_authorize_resource :foo => :bar
38
- end
39
-
40
- it "load_and_authorize_resource properly passes first argument as the resource name" do
41
- expect(cancan_resource_class = double).to receive(:load_and_authorize_resource)
42
- allow(CanCan::ControllerResource).to receive(:new).with(@controller, :project, :foo => :bar) {cancan_resource_class}
43
- expect(@controller_class).to receive(:before_filter).with({}) { |options, &block| block.call(@controller) }
44
- @controller_class.load_and_authorize_resource :project, :foo => :bar
45
- end
46
-
47
- it "load_and_authorize_resource with :prepend prepends the before filter" do
48
- expect(@controller_class).to receive(:prepend_before_filter).with({})
49
- @controller_class.load_and_authorize_resource :foo => :bar, :prepend => true
50
- end
51
-
52
- it "authorize_resource setups a before filter which passes call to ControllerResource" do
53
- expect(cancan_resource_class = double).to receive(:authorize_resource)
54
- allow(CanCan::ControllerResource).to receive(:new).with(@controller, nil, :foo => :bar) {cancan_resource_class}
55
- expect(@controller_class).to receive(:before_filter).with(:except => :show, :if => true) { |options, &block| block.call(@controller) }
56
- @controller_class.authorize_resource :foo => :bar, :except => :show, :if => true
57
- end
58
-
59
- it "load_resource setups a before filter which passes call to ControllerResource" do
60
- expect(cancan_resource_class = double).to receive(:load_resource)
61
- allow(CanCan::ControllerResource).to receive(:new).with(@controller, nil, :foo => :bar) {cancan_resource_class}
62
- expect(@controller_class).to receive(:before_filter).with(:only => [:show, :index], :unless => false) { |options, &block| block.call(@controller) }
63
- @controller_class.load_resource :foo => :bar, :only => [:show, :index], :unless => false
64
- end
65
-
66
- it "skip_authorization_check setups a before filter which sets @_authorized to true" do
67
- expect(@controller_class).to receive(:before_filter).with(:filter_options) { |options, &block| block.call(@controller) }
68
- @controller_class.skip_authorization_check(:filter_options)
69
- expect(@controller.instance_variable_get(:@_authorized)).to be(true)
70
- end
71
-
72
- it "check_authorization triggers AuthorizationNotPerformed in after filter" do
73
- expect(@controller_class).to receive(:after_filter).with(:only => [:test]) { |options, &block| block.call(@controller) }
74
- expect {
75
- @controller_class.check_authorization(:only => [:test])
76
- }.to raise_error(CanCan::AuthorizationNotPerformed)
77
- end
78
-
79
- it "check_authorization does not trigger AuthorizationNotPerformed when :if is false" do
80
- allow(@controller).to receive(:check_auth?) { false }
81
- allow(@controller_class).to receive(:after_filter).with({}) { |options, &block| block.call(@controller) }
82
- expect {
83
- @controller_class.check_authorization(:if => :check_auth?)
84
- }.not_to raise_error
85
- end
86
-
87
- it "check_authorization does not trigger AuthorizationNotPerformed when :unless is true" do
88
- allow(@controller).to receive(:engine_controller?) { true }
89
- expect(@controller_class).to receive(:after_filter).with({}) { |options, &block| block.call(@controller) }
90
- expect {
91
- @controller_class.check_authorization(:unless => :engine_controller?)
92
- }.not_to raise_error
93
- end
94
-
95
- it "check_authorization does not raise error when @_authorized is set" do
96
- @controller.instance_variable_set(:@_authorized, true)
97
- expect(@controller_class).to receive(:after_filter).with(:only => [:test]) { |options, &block| block.call(@controller) }
98
- expect {
99
- @controller_class.check_authorization(:only => [:test])
100
- }.not_to raise_error
101
- end
102
-
103
- it "cancan_resource_class is ControllerResource by default" do
104
- expect(@controller.class.cancan_resource_class).to eq(CanCan::ControllerResource)
105
- end
106
-
107
- it "cancan_resource_class is InheritedResource when class includes InheritedResources::Actions" do
108
- allow(@controller.class).to receive(:ancestors) { ["InheritedResources::Actions"] }
109
- expect(@controller.class.cancan_resource_class).to eq(CanCan::InheritedResource)
110
- end
111
-
112
- it "cancan_skipper is an empty hash with :authorize and :load options and remember changes" do
113
- expect(@controller_class.cancan_skipper).to eq({:authorize => {}, :load => {}})
114
- @controller_class.cancan_skipper[:load] = true
115
- expect(@controller_class.cancan_skipper[:load]).to be(true)
116
- end
117
-
118
- it "skip_authorize_resource adds itself to the cancan skipper with given model name and options" do
119
- @controller_class.skip_authorize_resource(:project, :only => [:index, :show])
120
- expect(@controller_class.cancan_skipper[:authorize][:project]).to eq({:only => [:index, :show]})
121
- @controller_class.skip_authorize_resource(:only => [:index, :show])
122
- expect(@controller_class.cancan_skipper[:authorize][nil]).to eq({:only => [:index, :show]})
123
- @controller_class.skip_authorize_resource(:article)
124
- expect(@controller_class.cancan_skipper[:authorize][:article]).to eq({})
125
- end
126
-
127
- it "skip_load_resource adds itself to the cancan skipper with given model name and options" do
128
- @controller_class.skip_load_resource(:project, :only => [:index, :show])
129
- expect(@controller_class.cancan_skipper[:load][:project]).to eq({:only => [:index, :show]})
130
- @controller_class.skip_load_resource(:only => [:index, :show])
131
- expect(@controller_class.cancan_skipper[:load][nil]).to eq({:only => [:index, :show]})
132
- @controller_class.skip_load_resource(:article)
133
- expect(@controller_class.cancan_skipper[:load][:article]).to eq({})
134
- end
135
-
136
- it "skip_load_and_authore_resource adds itself to the cancan skipper with given model name and options" do
137
- @controller_class.skip_load_and_authorize_resource(:project, :only => [:index, :show])
138
- expect(@controller_class.cancan_skipper[:load][:project]).to eq({:only => [:index, :show]})
139
- expect(@controller_class.cancan_skipper[:authorize][:project]).to eq({:only => [:index, :show]})
140
- end
141
- end
@@ -1,632 +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 => "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.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/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
-
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 "authorizes with :custom_action for parent collection action" do
235
- controller.instance_variable_set(:@category, :some_category)
236
- allow(controller).to receive(:authorize!).with(:custom_action, :some_category) { raise CanCan::AccessDenied }
237
-
238
- resource = CanCan::ControllerResource.new(controller, :category, :parent => true, :parent_action => :custom_action )
239
- expect { resource.authorize_resource }.to raise_error(CanCan::AccessDenied)
240
- end
241
-
242
- it "has the specified nested resource_class when using / for namespace" do
243
- module Admin
244
- class Dashboard; end
245
- end
246
- ability.can(:index, "admin/dashboard")
247
- params.merge!(:controller => "admin/dashboard")
248
- resource = CanCan::ControllerResource.new(controller, :authorize => true)
249
- expect(resource.send(:resource_class)).to eq(Admin::Dashboard)
250
- end
251
-
252
- it "does not build a single resource when on custom collection action even with id" do
253
- params.merge!(:action => "sort", :id => "123")
254
-
255
- resource = CanCan::ControllerResource.new(controller, :collection => [:sort, :list])
256
- resource.load_resource
257
- expect(controller.instance_variable_get(:@model)).to be_nil
258
- end
259
-
260
- it "loads a collection resource when on custom action with no id param" do
261
- allow(Model).to receive(:accessible_by).with(ability, :sort) { :found_models }
262
- params[:action] = "sort"
263
- resource = CanCan::ControllerResource.new(controller)
264
- resource.load_resource
265
- expect(controller.instance_variable_get(:@model)).to be_nil
266
- expect(controller.instance_variable_get(:@models)).to eq(:found_models)
267
- end
268
-
269
- it "loads parent resource through proper id parameter" do
270
- model = Model.new
271
- allow(Model).to receive(:find).with("1") { model }
272
-
273
- params.merge!(:controller => "categories", :model_id => 1)
274
- resource = CanCan::ControllerResource.new(controller, :model)
275
- resource.load_resource
276
- expect(controller.instance_variable_get(:@model)).to eq(model)
277
- end
278
-
279
- it "authorizes nested resource through parent association on index action" do
280
- controller.instance_variable_set(:@category, category = double)
281
- allow(controller).to receive(:authorize!).with(:index, category => Model) { raise CanCan::AccessDenied }
282
- resource = CanCan::ControllerResource.new(controller, :through => :category)
283
- expect { resource.authorize_resource }.to raise_error(CanCan::AccessDenied)
284
- end
285
- end
286
-
287
- context "on instance read actions" do
288
- before :each do
289
- params.merge!(:action => "show", :id => "123")
290
- end
291
-
292
- it "loads the resource into an instance variable if params[:id] is specified" do
293
- model = Model.new
294
- allow(Model).to receive(:find).with("123") { model }
295
-
296
- resource = CanCan::ControllerResource.new(controller)
297
- resource.load_resource
298
- expect(controller.instance_variable_get(:@model)).to eq(model)
299
- end
300
-
301
- it "does not load resource into an instance variable if already set" do
302
- controller.instance_variable_set(:@model, :some_model)
303
- resource = CanCan::ControllerResource.new(controller)
304
- resource.load_resource
305
- expect(controller.instance_variable_get(:@model)).to eq(:some_model)
306
- end
307
-
308
- it "loads resource for namespaced controller" do
309
- model = Model.new
310
- allow(Model).to receive(:find).with("123") { model }
311
- params.merge!(:controller => "admin/models")
312
-
313
- resource = CanCan::ControllerResource.new(controller)
314
- resource.load_resource
315
- expect(controller.instance_variable_get(:@model)).to eq(model)
316
- end
317
-
318
- it "performs authorization using controller action and loaded model" do
319
- controller.instance_variable_set(:@model, :some_model)
320
- allow(controller).to receive(:authorize!).with(:show, :some_model) { raise CanCan::AccessDenied }
321
-
322
- resource = CanCan::ControllerResource.new(controller)
323
- expect { resource.authorize_resource }.to raise_error(CanCan::AccessDenied)
324
- end
325
-
326
- it "performs authorization using controller action and non loaded model" do
327
- allow(controller).to receive(:authorize!).with(:show, Model) { raise CanCan::AccessDenied }
328
- resource = CanCan::ControllerResource.new(controller)
329
- expect { resource.authorize_resource }.to raise_error(CanCan::AccessDenied)
330
- end
331
-
332
- it "calls load_resource and authorize_resource for load_and_authorize_resource" do
333
- resource = CanCan::ControllerResource.new(controller)
334
- expect(resource).to receive(:load_resource)
335
- expect(resource).to receive(:authorize_resource)
336
- resource.load_and_authorize_resource
337
- end
338
-
339
- it "loads resource through the association of another parent resource using instance variable" do
340
- category = double(:models => {})
341
- controller.instance_variable_set(:@category, category)
342
- allow(category.models).to receive(:find).with("123") { :some_model }
343
- resource = CanCan::ControllerResource.new(controller, :through => :category)
344
- resource.load_resource
345
- expect(controller.instance_variable_get(:@model)).to eq(:some_model)
346
- end
347
-
348
- it "loads resource through the custom association name" do
349
- category = double(:custom_models => {})
350
- controller.instance_variable_set(:@category, category)
351
- allow(category.custom_models).to receive(:find).with("123") { :some_model }
352
- resource = CanCan::ControllerResource.new(controller, :through => :category, :through_association => :custom_models)
353
- resource.load_resource
354
- expect(controller.instance_variable_get(:@model)).to eq(:some_model)
355
- end
356
-
357
- it "loads resource through the association of another parent resource using method" do
358
- category = double(:models => {})
359
- allow(controller).to receive(:category) { category }
360
- allow(category.models).to receive(:find).with("123") { :some_model }
361
- resource = CanCan::ControllerResource.new(controller, :through => :category)
362
- resource.load_resource
363
- expect(controller.instance_variable_get(:@model)).to eq(:some_model)
364
- end
365
-
366
- it "does not load through parent resource if instance isn't loaded when shallow" do
367
- model = Model.new
368
- allow(Model).to receive(:find).with("123") { model }
369
-
370
- resource = CanCan::ControllerResource.new(controller, :through => :category, :shallow => true)
371
- resource.load_resource
372
- expect(controller.instance_variable_get(:@model)).to eq(model)
373
- end
374
-
375
- it "raises AccessDenied when attempting to load resource through nil" do
376
- resource = CanCan::ControllerResource.new(controller, :through => :category)
377
- expect {
378
- resource.load_resource
379
- }.to raise_error(CanCan::AccessDenied) { |exception|
380
- expect(exception.action).to eq(:show)
381
- expect(exception.subject).to eq(Model)
382
- }
383
- expect(controller.instance_variable_get(:@model)).to be_nil
384
- end
385
-
386
- it "loads through first matching if multiple are given" do
387
- category = double(:models => {})
388
- controller.instance_variable_set(:@category, category)
389
- allow(category.models).to receive(:find).with("123") { :some_model }
390
-
391
- resource = CanCan::ControllerResource.new(controller, :through => [:category, :user])
392
- resource.load_resource
393
- expect(controller.instance_variable_get(:@model)).to eq(:some_model)
394
- end
395
-
396
- it "finds record through has_one association with :singleton option without id param" do
397
- params.merge!(:id => nil)
398
-
399
- category = double(:model => :some_model)
400
- controller.instance_variable_set(:@category, category)
401
- resource = CanCan::ControllerResource.new(controller, :through => :category, :singleton => true)
402
- resource.load_resource
403
- expect(controller.instance_variable_get(:@model)).to eq(:some_model)
404
- end
405
-
406
- it "does not try to load resource for other action if params[:id] is undefined" do
407
- params.merge!(:action => 'list', :id => nil)
408
- resource = CanCan::ControllerResource.new(controller)
409
- resource.load_resource
410
- expect(controller.instance_variable_get(:@model)).to be_nil
411
- end
412
-
413
- it "finds record through has_one association with :singleton and :shallow options" do
414
- model = Model.new
415
- allow(Model).to receive(:find).with("123") { model }
416
-
417
- resource = CanCan::ControllerResource.new(controller, :through => :category, :singleton => true, :shallow => true)
418
- resource.load_resource
419
- expect(controller.instance_variable_get(:@model)).to eq(model)
420
- end
421
-
422
- it "loads the model using a custom class" do
423
- model = Model.new
424
- allow(Model).to receive(:find).with("123") { model }
425
-
426
- resource = CanCan::ControllerResource.new(controller, :class => Model)
427
- resource.load_resource
428
- expect(controller.instance_variable_get(:@model)).to eq(model)
429
- end
430
-
431
- it "loads the model using a custom namespaced class" do
432
- module Sub
433
- class Model < ::Model; end
434
- end
435
-
436
- model = Sub::Model.new
437
- allow(Sub::Model).to receive(:find).with("123") { model }
438
-
439
- resource = CanCan::ControllerResource.new(controller, :class => ::Sub::Model)
440
- resource.load_resource
441
- expect(controller.instance_variable_get(:@model)).to eq(model)
442
- end
443
-
444
- it "authorizes based on resource name if class is false" do
445
- allow(controller).to receive(:authorize!).with(:show, :model) { raise CanCan::AccessDenied }
446
- resource = CanCan::ControllerResource.new(controller, :class => false)
447
- expect { resource.authorize_resource }.to raise_error(CanCan::AccessDenied)
448
- end
449
-
450
- it "loads and authorize using custom instance name" do
451
- model = Model.new
452
- allow(Model).to receive(:find).with("123") { model }
453
-
454
- allow(controller).to receive(:authorize!).with(:show, model) { raise CanCan::AccessDenied }
455
- resource = CanCan::ControllerResource.new(controller, :instance_name => :custom_model)
456
- expect { resource.load_and_authorize_resource }.to raise_error(CanCan::AccessDenied)
457
- expect(controller.instance_variable_get(:@custom_model)).to eq(model)
458
- end
459
-
460
- it "loads resource using custom ID param" do
461
- model = Model.new
462
- allow(Model).to receive(:find).with("123") { model }
463
-
464
- params.merge!(:the_model => 123)
465
- resource = CanCan::ControllerResource.new(controller, :id_param => :the_model)
466
- resource.load_resource
467
- expect(controller.instance_variable_get(:@model)).to eq(model)
468
- end
469
-
470
- # CVE-2012-5664
471
- it "always converts id param to string" do
472
- params.merge!(:the_model => { :malicious => "I am" })
473
- resource = CanCan::ControllerResource.new(controller, :id_param => :the_model)
474
- expect(resource.send(:id_param).class).to eq(String)
475
- end
476
-
477
- it "should id param return nil if param is nil" do
478
- params.merge!(:the_model => nil)
479
- resource = CanCan::ControllerResource.new(controller, :id_param => :the_model)
480
- expect(resource.send(:id_param)).to be_nil
481
- end
482
-
483
- it "loads resource using custom find_by attribute" do
484
- model = Model.new
485
- allow(Model).to receive(:name).with('foo') { model }
486
-
487
- params.merge!(:action => "show", :id => "foo")
488
- resource = CanCan::ControllerResource.new(controller, :find_by => :name)
489
- resource.load_resource
490
- expect(controller.instance_variable_get(:@model)).to eq(model)
491
- end
492
-
493
- it "allows full find method to be passed into find_by option" do
494
- model = Model.new
495
- allow(Model).to receive(:find_by_name).with('foo') { model }
496
-
497
- params.merge!(:action => "show", :id => "foo")
498
- resource = CanCan::ControllerResource.new(controller, :find_by => :find_by_name)
499
- resource.load_resource
500
- expect(controller.instance_variable_get(:@model)).to eq(model)
501
- end
502
- end
503
-
504
- it "calls the santitizer when the parameter hash matches our object" do
505
- params.merge!(:action => 'create', :model => { :name => 'test' })
506
- allow(controller).to receive(:create_params).and_return({})
507
-
508
- resource = CanCan::ControllerResource.new(controller)
509
- resource.load_resource
510
- expect(controller.instance_variable_get(:@model).name).to eq nil
511
- end
512
-
513
- it "santitizes correctly when the instance name is overriden" do
514
- params.merge!(:action => 'create', :custom_name => {:name => "foobar"})
515
- allow(controller).to receive(:create_params).and_return({})
516
-
517
- resource = CanCan::ControllerResource.new(controller, :instance_name => :custom_name)
518
- resource.load_resource
519
- expect(controller.instance_variable_get(:@custom_name).name).to eq nil
520
- end
521
-
522
- it "calls the santitize method on non-save actions when required" do
523
- params.merge!(:action => 'new', :model => { :name => 'test' })
524
-
525
- allow(controller).to receive(:resource_params).and_return({})
526
- resource = CanCan::ControllerResource.new(controller)
527
- resource.load_resource
528
- expect(controller.instance_variable_get(:@model).name).to eq nil
529
- end
530
-
531
- it "doesn't sanitize parameters on non-save actions when not required" do
532
- params.merge!(:action => 'new', :not_our_model => { :name => 'test' })
533
- allow(controller).to receive(:resource_params).and_raise
534
-
535
- resource = CanCan::ControllerResource.new(controller)
536
- expect {
537
- resource.load_resource
538
- }.to_not raise_error
539
- end
540
-
541
- it "is a parent resource when name is provided which doesn't match controller" do
542
- resource = CanCan::ControllerResource.new(controller, :category)
543
- expect(resource).to be_parent
544
- end
545
-
546
- it "does not be a parent resource when name is provided which matches controller" do
547
- resource = CanCan::ControllerResource.new(controller, :model)
548
- expect(resource).to_not be_parent
549
- end
550
-
551
- it "is parent if specified in options" do
552
- resource = CanCan::ControllerResource.new(controller, :model, {:parent => true})
553
- expect(resource).to be_parent
554
- end
555
-
556
- it "does not be parent if specified in options" do
557
- resource = CanCan::ControllerResource.new(controller, :category, {:parent => false})
558
- expect(resource).to_not be_parent
559
- end
560
-
561
- it "has the specified resource_class if 'name' is passed to load_resource" do
562
- class Section; end
563
- resource = CanCan::ControllerResource.new(controller, :section)
564
- expect(resource.send(:resource_class)).to eq(Section)
565
- end
566
-
567
- it "raises ImplementationRemoved when adding :name option" do
568
- expect {
569
- CanCan::ControllerResource.new(controller, :name => :foo)
570
- }.to raise_error(CanCan::ImplementationRemoved)
571
- end
572
-
573
- it "raises ImplementationRemoved exception when specifying :resource option since it is no longer used" do
574
- expect {
575
- CanCan::ControllerResource.new(controller, :resource => Model)
576
- }.to raise_error(CanCan::ImplementationRemoved)
577
- end
578
-
579
- it "raises ImplementationRemoved exception when passing :nested option" do
580
- expect {
581
- CanCan::ControllerResource.new(controller, :nested => :model)
582
- }.to raise_error(CanCan::ImplementationRemoved)
583
- end
584
-
585
- it "skips resource behavior for :only actions in array" do
586
- allow(controller_class).to receive(:cancan_skipper) { {:load => {nil => {:only => [:index, :show]}}} }
587
- params.merge!(:action => "index")
588
- expect(CanCan::ControllerResource.new(controller).skip?(:load)).to be(true)
589
- expect(CanCan::ControllerResource.new(controller, :some_resource).skip?(:load)).to be(false)
590
- params.merge!(:action => "show")
591
- expect(CanCan::ControllerResource.new(controller).skip?(:load)).to be(true)
592
- params.merge!(:action => "other_action")
593
- expect(CanCan::ControllerResource.new(controller).skip?(:load)).to be_falsey
594
- end
595
-
596
- it "skips resource behavior for :only one action on resource" do
597
- allow(controller_class).to receive(:cancan_skipper) { {:authorize => {:model => {:only => :index}}} }
598
- params.merge!(:action => "index")
599
- expect(CanCan::ControllerResource.new(controller).skip?(:authorize)).to be(false)
600
- expect(CanCan::ControllerResource.new(controller, :model).skip?(:authorize)).to be(true)
601
- params.merge!(:action => "other_action")
602
- expect(CanCan::ControllerResource.new(controller, :model).skip?(:authorize)).to be_falsey
603
- end
604
-
605
- it "skips resource behavior :except actions in array" do
606
- allow(controller_class).to receive(:cancan_skipper) { {:load => {nil => {:except => [:index, :show]}}} }
607
- params.merge!(:action => "index")
608
- expect(CanCan::ControllerResource.new(controller).skip?(:load)).to be_falsey
609
- params.merge!(:action => "show")
610
- expect(CanCan::ControllerResource.new(controller).skip?(:load)).to be_falsey
611
- params.merge!(:action => "other_action")
612
- expect(CanCan::ControllerResource.new(controller).skip?(:load)).to be(true)
613
- expect(CanCan::ControllerResource.new(controller, :some_resource).skip?(:load)).to be(false)
614
- end
615
-
616
- it "skips resource behavior :except one action on resource" do
617
- allow(controller_class).to receive(:cancan_skipper) { {:authorize => {:model => {:except => :index}}} }
618
- params.merge!(:action => "index")
619
- expect(CanCan::ControllerResource.new(controller, :model).skip?(:authorize)).to be_falsey
620
- params.merge!(:action => "other_action")
621
- expect(CanCan::ControllerResource.new(controller).skip?(:authorize)).to be(false)
622
- expect(CanCan::ControllerResource.new(controller, :model).skip?(:authorize)).to be(true)
623
- end
624
-
625
- it "skips loading and authorization" do
626
- allow(controller_class).to receive(:cancan_skipper) { {:authorize => {nil => {}}, :load => {nil => {}}} }
627
- params.merge!(:action => "new")
628
- resource = CanCan::ControllerResource.new(controller)
629
- expect { resource.load_and_authorize_resource }.not_to raise_error
630
- expect(controller.instance_variable_get(:@model)).to be_nil
631
- end
632
- end