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