cancancan 1.13.1 → 3.1.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 (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