cancancan 1.11.0 → 2.3.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 +5 -5
- data/cancancan.gemspec +15 -19
- data/lib/cancan/ability/actions.rb +91 -0
- data/lib/cancan/ability/rules.rb +85 -0
- data/lib/cancan/ability.rb +74 -136
- data/lib/cancan/conditions_matcher.rb +93 -0
- data/lib/cancan/controller_additions.rb +34 -40
- data/lib/cancan/controller_resource.rb +47 -212
- data/lib/cancan/controller_resource_builder.rb +24 -0
- data/lib/cancan/controller_resource_finder.rb +40 -0
- data/lib/cancan/controller_resource_loader.rb +116 -0
- data/lib/cancan/controller_resource_name_finder.rb +21 -0
- data/lib/cancan/controller_resource_sanitizer.rb +30 -0
- data/lib/cancan/exceptions.rb +7 -3
- data/lib/cancan/matchers.rb +12 -3
- data/lib/cancan/model_adapters/abstract_adapter.rb +8 -8
- data/lib/cancan/model_adapters/active_record_4_adapter.rb +33 -10
- data/lib/cancan/model_adapters/active_record_5_adapter.rb +70 -0
- data/lib/cancan/model_adapters/active_record_adapter.rb +41 -81
- data/lib/cancan/model_adapters/can_can/model_adapters/active_record_adapter/joins.rb +39 -0
- data/lib/cancan/model_adapters/conditions_extractor.rb +75 -0
- data/lib/cancan/model_additions.rb +0 -1
- data/lib/cancan/rule.rb +36 -92
- data/lib/cancan/rules_compressor.rb +20 -0
- data/lib/cancan/version.rb +1 -1
- data/lib/cancan.rb +5 -12
- data/lib/generators/cancan/ability/ability_generator.rb +1 -1
- metadata +54 -65
- data/.gitignore +0 -15
- data/.rspec +0 -1
- data/.travis.yml +0 -55
- data/Appraisals +0 -136
- data/CHANGELOG.rdoc +0 -503
- data/CONTRIBUTING.md +0 -23
- data/Gemfile +0 -3
- data/LICENSE +0 -22
- data/README.md +0 -188
- data/Rakefile +0 -9
- data/gemfiles/activerecord_3.0.gemfile +0 -18
- data/gemfiles/activerecord_3.1.gemfile +0 -20
- data/gemfiles/activerecord_3.2.gemfile +0 -20
- data/gemfiles/activerecord_4.0.gemfile +0 -17
- data/gemfiles/activerecord_4.1.gemfile +0 -17
- data/gemfiles/activerecord_4.2.gemfile +0 -18
- data/gemfiles/datamapper_1.x.gemfile +0 -14
- data/gemfiles/mongoid_2.x.gemfile +0 -20
- data/gemfiles/sequel_3.x.gemfile +0 -20
- data/lib/cancan/inherited_resource.rb +0 -20
- data/lib/cancan/model_adapters/active_record_3_adapter.rb +0 -47
- data/lib/cancan/model_adapters/data_mapper_adapter.rb +0 -34
- data/lib/cancan/model_adapters/mongoid_adapter.rb +0 -54
- data/lib/cancan/model_adapters/sequel_adapter.rb +0 -87
- data/spec/README.rdoc +0 -27
- data/spec/cancan/ability_spec.rb +0 -487
- data/spec/cancan/controller_additions_spec.rb +0 -141
- data/spec/cancan/controller_resource_spec.rb +0 -632
- data/spec/cancan/exceptions_spec.rb +0 -58
- data/spec/cancan/inherited_resource_spec.rb +0 -71
- data/spec/cancan/matchers_spec.rb +0 -29
- data/spec/cancan/model_adapters/active_record_4_adapter_spec.rb +0 -85
- data/spec/cancan/model_adapters/active_record_adapter_spec.rb +0 -446
- data/spec/cancan/model_adapters/data_mapper_adapter_spec.rb +0 -119
- data/spec/cancan/model_adapters/default_adapter_spec.rb +0 -7
- data/spec/cancan/model_adapters/mongoid_adapter_spec.rb +0 -227
- data/spec/cancan/model_adapters/sequel_adapter_spec.rb +0 -132
- data/spec/cancan/rule_spec.rb +0 -52
- data/spec/matchers.rb +0 -13
- data/spec/spec.opts +0 -2
- data/spec/spec_helper.rb +0 -28
- data/spec/support/ability.rb +0 -7
data/spec/cancan/ability_spec.rb
DELETED
@@ -1,487 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
|
3
|
-
describe CanCan::Ability do
|
4
|
-
before(:each) do
|
5
|
-
(@ability = double).extend(CanCan::Ability)
|
6
|
-
end
|
7
|
-
|
8
|
-
it "is able to :read anything" do
|
9
|
-
@ability.can :read, :all
|
10
|
-
expect(@ability.can?(:read, String)).to be(true)
|
11
|
-
expect(@ability.can?(:read, 123)).to be(true)
|
12
|
-
end
|
13
|
-
|
14
|
-
it "does not have permission to do something it doesn't know about" do
|
15
|
-
expect(@ability.can?(:foodfight, String)).to be(false)
|
16
|
-
end
|
17
|
-
|
18
|
-
it "passes true to `can?` when non false/nil is returned in block" do
|
19
|
-
@ability.can :read, :all
|
20
|
-
@ability.can :read, Symbol do |sym|
|
21
|
-
"foo" # TODO test that sym is nil when no instance is passed
|
22
|
-
end
|
23
|
-
expect(@ability.can?(:read, :some_symbol)).to be(true)
|
24
|
-
end
|
25
|
-
|
26
|
-
it "passes nil to a block when no instance is passed" do
|
27
|
-
@ability.can :read, Symbol do |sym|
|
28
|
-
expect(sym).to be_nil
|
29
|
-
true
|
30
|
-
end
|
31
|
-
expect(@ability.can?(:read, Symbol)).to be(true)
|
32
|
-
end
|
33
|
-
|
34
|
-
it "passes to previous rule, if block returns false or nil" do
|
35
|
-
@ability.can :read, Symbol
|
36
|
-
@ability.can :read, Integer do |i|
|
37
|
-
i < 5
|
38
|
-
end
|
39
|
-
@ability.can :read, Integer do |i|
|
40
|
-
i > 10
|
41
|
-
end
|
42
|
-
expect(@ability.can?(:read, Symbol)).to be(true)
|
43
|
-
expect(@ability.can?(:read, 11)).to be(true)
|
44
|
-
expect(@ability.can?(:read, 1)).to be(true)
|
45
|
-
expect(@ability.can?(:read, 6)).to be(false)
|
46
|
-
end
|
47
|
-
|
48
|
-
it "does not pass class with object if :all objects are accepted" do
|
49
|
-
@ability.can :preview, :all do |object|
|
50
|
-
expect(object).to eq(123)
|
51
|
-
@block_called = true
|
52
|
-
end
|
53
|
-
@ability.can?(:preview, 123)
|
54
|
-
expect(@block_called).to be(true)
|
55
|
-
end
|
56
|
-
|
57
|
-
it "does not call block when only class is passed, only return true" do
|
58
|
-
@block_called = false
|
59
|
-
@ability.can :preview, :all do |object|
|
60
|
-
@block_called = true
|
61
|
-
end
|
62
|
-
expect(@ability.can?(:preview, Hash)).to be(true)
|
63
|
-
expect(@block_called).to be(false)
|
64
|
-
end
|
65
|
-
|
66
|
-
it "passes only object for global manage actions" do
|
67
|
-
@ability.can :manage, String do |object|
|
68
|
-
expect(object).to eq("foo")
|
69
|
-
@block_called = true
|
70
|
-
end
|
71
|
-
expect(@ability.can?(:stuff, "foo")).to be(true)
|
72
|
-
expect(@block_called).to be(true)
|
73
|
-
end
|
74
|
-
|
75
|
-
it "makes alias for update or destroy actions to modify action" do
|
76
|
-
@ability.alias_action :update, :destroy, :to => :modify
|
77
|
-
@ability.can :modify, :all
|
78
|
-
expect(@ability.can?(:update, 123)).to be(true)
|
79
|
-
expect(@ability.can?(:destroy, 123)).to be(true)
|
80
|
-
end
|
81
|
-
|
82
|
-
it "allows deeply nested aliased actions" do
|
83
|
-
@ability.alias_action :increment, :to => :sort
|
84
|
-
@ability.alias_action :sort, :to => :modify
|
85
|
-
@ability.can :modify, :all
|
86
|
-
expect(@ability.can?(:increment, 123)).to be(true)
|
87
|
-
end
|
88
|
-
|
89
|
-
it "raises an Error if alias target is an exist action" do
|
90
|
-
expect { @ability.alias_action :show, :to => :show }.to raise_error(CanCan::Error, "You can't specify target (show) as alias because it is real action name")
|
91
|
-
end
|
92
|
-
|
93
|
-
it "always calls block with arguments when passing no arguments to can" do
|
94
|
-
@ability.can do |action, object_class, object|
|
95
|
-
expect(action).to eq(:foo)
|
96
|
-
expect(object_class).to eq(123.class)
|
97
|
-
expect(object).to eq(123)
|
98
|
-
@block_called = true
|
99
|
-
end
|
100
|
-
@ability.can?(:foo, 123)
|
101
|
-
expect(@block_called).to be(true)
|
102
|
-
end
|
103
|
-
|
104
|
-
it "passes nil to object when comparing class with can check" do
|
105
|
-
@ability.can do |action, object_class, object|
|
106
|
-
expect(action).to eq(:foo)
|
107
|
-
expect(object_class).to eq(Hash)
|
108
|
-
expect(object).to be_nil
|
109
|
-
@block_called = true
|
110
|
-
end
|
111
|
-
@ability.can?(:foo, Hash)
|
112
|
-
expect(@block_called).to be(true)
|
113
|
-
end
|
114
|
-
|
115
|
-
it "automatically makes alias for index and show into read calls" do
|
116
|
-
@ability.can :read, :all
|
117
|
-
expect(@ability.can?(:index, 123)).to be(true)
|
118
|
-
expect(@ability.can?(:show, 123)).to be(true)
|
119
|
-
end
|
120
|
-
|
121
|
-
it "automatically makes alias for new and edit into create and update respectively" do
|
122
|
-
@ability.can :create, :all
|
123
|
-
@ability.can :update, :all
|
124
|
-
expect(@ability.can?(:new, 123)).to be(true)
|
125
|
-
expect(@ability.can?(:edit, 123)).to be(true)
|
126
|
-
end
|
127
|
-
|
128
|
-
it "does not respond to prepare (now using initialize)" do
|
129
|
-
expect(@ability).to_not respond_to(:prepare)
|
130
|
-
end
|
131
|
-
|
132
|
-
it "offers cannot? method which is simply invert of can?" do
|
133
|
-
expect(@ability.cannot?(:tie, String)).to be(true)
|
134
|
-
end
|
135
|
-
|
136
|
-
it "is able to specify multiple actions and match any" do
|
137
|
-
@ability.can [:read, :update], :all
|
138
|
-
expect(@ability.can?(:read, 123)).to be(true)
|
139
|
-
expect(@ability.can?(:update, 123)).to be(true)
|
140
|
-
expect(@ability.can?(:count, 123)).to be(false)
|
141
|
-
end
|
142
|
-
|
143
|
-
it "is able to specify multiple classes and match any" do
|
144
|
-
@ability.can :update, [String, Range]
|
145
|
-
expect(@ability.can?(:update, "foo")).to be(true)
|
146
|
-
expect(@ability.can?(:update, 1..3)).to be(true)
|
147
|
-
expect(@ability.can?(:update, 123)).to be(false)
|
148
|
-
end
|
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
|
-
|
158
|
-
it "supports custom objects in the rule" do
|
159
|
-
@ability.can :read, :stats
|
160
|
-
expect(@ability.can?(:read, :stats)).to be(true)
|
161
|
-
expect(@ability.can?(:update, :stats)).to be(false)
|
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)
|
165
|
-
end
|
166
|
-
|
167
|
-
it "checks ancestors of class" do
|
168
|
-
@ability.can :read, Numeric
|
169
|
-
expect(@ability.can?(:read, Integer)).to be(true)
|
170
|
-
expect(@ability.can?(:read, 1.23)).to be(true)
|
171
|
-
expect(@ability.can?(:read, "foo")).to be(false)
|
172
|
-
expect(@ability.can?(:read, {:any => [Integer, String]})).to be(true)
|
173
|
-
end
|
174
|
-
|
175
|
-
it "supports 'cannot' method to define what user cannot do" do
|
176
|
-
@ability.can :read, :all
|
177
|
-
@ability.cannot :read, Integer
|
178
|
-
expect(@ability.can?(:read, "foo")).to be(true)
|
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)
|
183
|
-
end
|
184
|
-
|
185
|
-
it "passes to previous rule, if block returns false or nil" do
|
186
|
-
@ability.can :read, :all
|
187
|
-
@ability.cannot :read, Integer do |int|
|
188
|
-
int > 10 ? nil : ( int > 5 )
|
189
|
-
end
|
190
|
-
|
191
|
-
expect(@ability.can?(:read, "foo")).to be(true)
|
192
|
-
expect(@ability.can?(:read, 3)).to be(true)
|
193
|
-
expect(@ability.can?(:read, 8)).to be(false)
|
194
|
-
expect(@ability.can?(:read, 123)).to be(true)
|
195
|
-
expect(@ability.can?(:read, {:any => [123, 8]})).to be(true)
|
196
|
-
expect(@ability.can?(:read, {:any => [8, 9]})).to be(false)
|
197
|
-
end
|
198
|
-
|
199
|
-
it "always returns `false` for single cannot definition" do
|
200
|
-
@ability.cannot :read, Integer do |int|
|
201
|
-
int > 10 ? nil : ( int > 5 )
|
202
|
-
end
|
203
|
-
expect(@ability.can?(:read, "foo")).to be(false)
|
204
|
-
expect(@ability.can?(:read, 3)).to be(false)
|
205
|
-
expect(@ability.can?(:read, 8)).to be(false)
|
206
|
-
expect(@ability.can?(:read, 123)).to be(false)
|
207
|
-
end
|
208
|
-
|
209
|
-
it "passes to previous cannot definition, if block returns false or nil" do
|
210
|
-
@ability.cannot :read, :all
|
211
|
-
@ability.can :read, Integer do |int|
|
212
|
-
int > 10 ? nil : ( int > 5 )
|
213
|
-
end
|
214
|
-
expect(@ability.can?(:read, "foo")).to be(false)
|
215
|
-
expect(@ability.can?(:read, 3)).to be(false)
|
216
|
-
expect(@ability.can?(:read, 10)).to be(true)
|
217
|
-
expect(@ability.can?(:read, 123)).to be(false)
|
218
|
-
end
|
219
|
-
|
220
|
-
it "appends aliased actions" do
|
221
|
-
@ability.alias_action :update, :to => :modify
|
222
|
-
@ability.alias_action :destroy, :to => :modify
|
223
|
-
expect(@ability.aliased_actions[:modify]).to eq([:update, :destroy])
|
224
|
-
end
|
225
|
-
|
226
|
-
it "clears aliased actions" do
|
227
|
-
@ability.alias_action :update, :to => :modify
|
228
|
-
@ability.clear_aliased_actions
|
229
|
-
expect(@ability.aliased_actions[:modify]).to be_nil
|
230
|
-
end
|
231
|
-
|
232
|
-
it "passes additional arguments to block from can?" do
|
233
|
-
@ability.can :read, Integer do |int, x|
|
234
|
-
int > x
|
235
|
-
end
|
236
|
-
|
237
|
-
expect(@ability.can?(:read, 2, 1)).to be(true)
|
238
|
-
expect(@ability.can?(:read, 2, 3)).to be(false)
|
239
|
-
expect(@ability.can?(:read, {:any => [4, 5]}, 3)).to be(true)
|
240
|
-
expect(@ability.can?(:read, {:any => [2, 3]}, 3)).to be(false)
|
241
|
-
end
|
242
|
-
|
243
|
-
it "uses conditions as third parameter and determine abilities from it" do
|
244
|
-
@ability.can :read, Range, :begin => 1, :end => 3
|
245
|
-
|
246
|
-
expect(@ability.can?(:read, 1..3)).to be(true)
|
247
|
-
expect(@ability.can?(:read, 1..4)).to be(false)
|
248
|
-
expect(@ability.can?(:read, Range)).to be(true)
|
249
|
-
expect(@ability.can?(:read, {:any => [1..3, 1..4]})).to be(true)
|
250
|
-
expect(@ability.can?(:read, {:any => [1..4, 2..4]})).to be(false)
|
251
|
-
end
|
252
|
-
|
253
|
-
it "allows an array of options in conditions hash" do
|
254
|
-
@ability.can :read, Range, :begin => [1, 3, 5]
|
255
|
-
|
256
|
-
expect(@ability.can?(:read, 1..3)).to be(true)
|
257
|
-
expect(@ability.can?(:read, 2..4)).to be(false)
|
258
|
-
expect(@ability.can?(:read, 3..5)).to be(true)
|
259
|
-
expect(@ability.can?(:read, {:any => [2..4, 3..5]})).to be(true)
|
260
|
-
expect(@ability.can?(:read, {:any => [2..4, 2..5]})).to be(false)
|
261
|
-
end
|
262
|
-
|
263
|
-
it "allows a range of options in conditions hash" do
|
264
|
-
@ability.can :read, Range, :begin => 1..3
|
265
|
-
expect(@ability.can?(:read, 1..10)).to be(true)
|
266
|
-
expect(@ability.can?(:read, 3..30)).to be(true)
|
267
|
-
expect(@ability.can?(:read, 4..40)).to be(false)
|
268
|
-
end
|
269
|
-
|
270
|
-
it "allows nested hashes in conditions hash" do
|
271
|
-
@ability.can :read, Range, :begin => { :to_i => 5 }
|
272
|
-
expect(@ability.can?(:read, 5..7)).to be(true)
|
273
|
-
expect(@ability.can?(:read, 6..8)).to be(false)
|
274
|
-
end
|
275
|
-
|
276
|
-
it "matches any element passed in to nesting if it's an array (for has_many associations)" do
|
277
|
-
@ability.can :read, Range, :to_a => { :to_i => 3 }
|
278
|
-
expect(@ability.can?(:read, 1..5)).to be(true)
|
279
|
-
expect(@ability.can?(:read, 4..6)).to be(false)
|
280
|
-
end
|
281
|
-
|
282
|
-
it "accepts a set as a condition value" do
|
283
|
-
expect(object_with_foo_2 = double(:foo => 2)).to receive(:foo)
|
284
|
-
expect(object_with_foo_3 = double(:foo => 3)).to receive(:foo)
|
285
|
-
@ability.can :read, Object, :foo => [1, 2, 5].to_set
|
286
|
-
expect(@ability.can?(:read, object_with_foo_2)).to be(true)
|
287
|
-
expect(@ability.can?(:read, object_with_foo_3)).to be(false)
|
288
|
-
end
|
289
|
-
|
290
|
-
it "does not match subjects return nil for methods that must match nested a nested conditions hash" do
|
291
|
-
expect(object_with_foo = double(:foo => :bar)).to receive(:foo)
|
292
|
-
@ability.can :read, Array, :first => { :foo => :bar }
|
293
|
-
expect(@ability.can?(:read, [object_with_foo])).to be(true)
|
294
|
-
expect(@ability.can?(:read, [])).to be(false)
|
295
|
-
end
|
296
|
-
|
297
|
-
it "matches strings but not substrings specified in a conditions hash" do
|
298
|
-
@ability.can :read, String, :presence => "declassified"
|
299
|
-
expect(@ability.can?(:read, "declassified")).to be(true)
|
300
|
-
expect(@ability.can?(:read, "classified")).to be(false)
|
301
|
-
end
|
302
|
-
|
303
|
-
it "does not stop at cannot definition when comparing class" do
|
304
|
-
@ability.can :read, Range
|
305
|
-
@ability.cannot :read, Range, :begin => 1
|
306
|
-
expect(@ability.can?(:read, 2..5)).to be(true)
|
307
|
-
expect(@ability.can?(:read, 1..5)).to be(false)
|
308
|
-
expect(@ability.can?(:read, Range)).to be(true)
|
309
|
-
end
|
310
|
-
|
311
|
-
it "stops at cannot definition when no hash is present" do
|
312
|
-
@ability.can :read, :all
|
313
|
-
@ability.cannot :read, Range
|
314
|
-
expect(@ability.can?(:read, 1..5)).to be(false)
|
315
|
-
expect(@ability.can?(:read, Range)).to be(false)
|
316
|
-
end
|
317
|
-
|
318
|
-
it "allows to check ability for Module" do
|
319
|
-
module B; end
|
320
|
-
class A; include B; end
|
321
|
-
@ability.can :read, B
|
322
|
-
expect(@ability.can?(:read, A)).to be(true)
|
323
|
-
expect(@ability.can?(:read, A.new)).to be(true)
|
324
|
-
end
|
325
|
-
|
326
|
-
it "passes nil to a block for ability on Module when no instance is passed" do
|
327
|
-
module B; end
|
328
|
-
class A; include B; end
|
329
|
-
@ability.can :read, B do |sym|
|
330
|
-
expect(sym).to be_nil
|
331
|
-
true
|
332
|
-
end
|
333
|
-
expect(@ability.can?(:read, B)).to be(true)
|
334
|
-
expect(@ability.can?(:read, A)).to be(true)
|
335
|
-
end
|
336
|
-
|
337
|
-
it "checks permissions through association when passing a hash of subjects" do
|
338
|
-
@ability.can :read, Range, :string => {:length => 3}
|
339
|
-
|
340
|
-
expect(@ability.can?(:read, "foo" => Range)).to be(true)
|
341
|
-
expect(@ability.can?(:read, "foobar" => Range)).to be(false)
|
342
|
-
expect(@ability.can?(:read, 123 => Range)).to be(true)
|
343
|
-
expect(@ability.can?(:read, {:any => [{"foo" => Range}, {"foobar" => Range}]})).to be(true)
|
344
|
-
expect(@ability.can?(:read, {:any => [{"food" => Range}, {"foobar" => Range}]})).to be(false)
|
345
|
-
end
|
346
|
-
|
347
|
-
it "checks permissions correctly when passing a hash of subjects with multiple definitions" do
|
348
|
-
@ability.can :read, Range, :string => {:length => 4}
|
349
|
-
@ability.can [:create, :read], Range, :string => {:upcase => 'FOO'}
|
350
|
-
|
351
|
-
expect(@ability.can?(:read, "foo" => Range)).to be(true)
|
352
|
-
expect(@ability.can?(:read, "foobar" => Range)).to be(false)
|
353
|
-
expect(@ability.can?(:read, 1234 => Range)).to be(true)
|
354
|
-
expect(@ability.can?(:read, {:any => [{"foo" => Range}, {"foobar" => Range}]})).to be(true)
|
355
|
-
expect(@ability.can?(:read, {:any => [{"foo.bar" => Range}, {"foobar" => Range}]})).to be(false)
|
356
|
-
end
|
357
|
-
|
358
|
-
it "allows to check ability on Hash-like object" do
|
359
|
-
class Container < Hash; end
|
360
|
-
@ability.can :read, Container
|
361
|
-
expect(@ability.can?(:read, Container.new)).to be(true)
|
362
|
-
end
|
363
|
-
|
364
|
-
it "has initial attributes based on hash conditions of 'new' action" do
|
365
|
-
@ability.can :manage, Range, :foo => "foo", :hash => {:skip => "hashes"}
|
366
|
-
@ability.can :create, Range, :bar => 123, :array => %w[skip arrays]
|
367
|
-
@ability.can :new, Range, :baz => "baz", :range => 1..3
|
368
|
-
@ability.cannot :new, Range, :ignore => "me"
|
369
|
-
expect(@ability.attributes_for(:new, Range)).to eq({:foo => "foo", :bar => 123, :baz => "baz"})
|
370
|
-
end
|
371
|
-
|
372
|
-
it "raises access denied exception if ability us unauthorized to perform a certain action" do
|
373
|
-
begin
|
374
|
-
@ability.authorize! :read, :foo, 1, 2, 3, :message => "Access denied!"
|
375
|
-
rescue CanCan::AccessDenied => e
|
376
|
-
expect(e.message).to eq("Access denied!")
|
377
|
-
expect(e.action).to eq(:read)
|
378
|
-
expect(e.subject).to eq(:foo)
|
379
|
-
else
|
380
|
-
fail "Expected CanCan::AccessDenied exception to be raised"
|
381
|
-
end
|
382
|
-
end
|
383
|
-
|
384
|
-
it "does not raise access denied exception if ability is authorized to perform an action and return subject" do
|
385
|
-
@ability.can :read, :foo
|
386
|
-
expect {
|
387
|
-
expect(@ability.authorize!(:read, :foo)).to eq(:foo)
|
388
|
-
}.to_not raise_error
|
389
|
-
end
|
390
|
-
|
391
|
-
it "knows when block is used in conditions" do
|
392
|
-
@ability.can :read, :foo
|
393
|
-
expect(@ability).to_not have_block(:read, :foo)
|
394
|
-
@ability.can :read, :foo do |foo|
|
395
|
-
false
|
396
|
-
end
|
397
|
-
expect(@ability).to have_block(:read, :foo)
|
398
|
-
end
|
399
|
-
|
400
|
-
it "knows when raw sql is used in conditions" do
|
401
|
-
@ability.can :read, :foo
|
402
|
-
expect(@ability).to_not have_raw_sql(:read, :foo)
|
403
|
-
@ability.can :read, :foo, 'false'
|
404
|
-
expect(@ability).to have_raw_sql(:read, :foo)
|
405
|
-
end
|
406
|
-
|
407
|
-
it "raises access denied exception with default message if not specified" do
|
408
|
-
begin
|
409
|
-
@ability.authorize! :read, :foo
|
410
|
-
rescue CanCan::AccessDenied => e
|
411
|
-
e.default_message = "Access denied!"
|
412
|
-
expect(e.message).to eq("Access denied!")
|
413
|
-
else
|
414
|
-
fail "Expected CanCan::AccessDenied exception to be raised"
|
415
|
-
end
|
416
|
-
end
|
417
|
-
|
418
|
-
it "determines model adapterO class by asking AbstractAdapter" do
|
419
|
-
adapter_class, model_class = double, double
|
420
|
-
allow(CanCan::ModelAdapters::AbstractAdapter).to receive(:adapter_class).with(model_class) { adapter_class }
|
421
|
-
allow(adapter_class).to receive(:new).with(model_class, []) { :adapter_instance }
|
422
|
-
expect(@ability.model_adapter(model_class, :read)).to eq(:adapter_instance)
|
423
|
-
end
|
424
|
-
|
425
|
-
it "raises an error when attempting to use a block with a hash condition since it's not likely what they want" do
|
426
|
-
expect {
|
427
|
-
@ability.can :read, Array, :published => true do
|
428
|
-
false
|
429
|
-
end
|
430
|
-
}.to raise_error(CanCan::Error, "You are not able to supply a block with a hash of conditions in read Array ability. Use either one.")
|
431
|
-
end
|
432
|
-
|
433
|
-
describe "unauthorized message" do
|
434
|
-
after(:each) do
|
435
|
-
I18n.backend = nil
|
436
|
-
end
|
437
|
-
|
438
|
-
it "uses action/subject in i18n" do
|
439
|
-
I18n.backend.store_translations :en, :unauthorized => {:update => {:array => "foo"}}
|
440
|
-
expect(@ability.unauthorized_message(:update, Array)).to eq("foo")
|
441
|
-
expect(@ability.unauthorized_message(:update, [1, 2, 3])).to eq("foo")
|
442
|
-
expect(@ability.unauthorized_message(:update, :missing)).to be_nil
|
443
|
-
end
|
444
|
-
|
445
|
-
it "uses symbol as subject directly" do
|
446
|
-
I18n.backend.store_translations :en, :unauthorized => {:has => {:cheezburger => "Nom nom nom. I eated it."}}
|
447
|
-
expect(@ability.unauthorized_message(:has, :cheezburger)).to eq("Nom nom nom. I eated it.")
|
448
|
-
end
|
449
|
-
|
450
|
-
it "falls back to 'manage' and 'all'" do
|
451
|
-
I18n.backend.store_translations :en, :unauthorized => {
|
452
|
-
:manage => {:all => "manage all", :array => "manage array"},
|
453
|
-
:update => {:all => "update all", :array => "update array"}
|
454
|
-
}
|
455
|
-
expect(@ability.unauthorized_message(:update, Array)).to eq("update array")
|
456
|
-
expect(@ability.unauthorized_message(:update, Hash)).to eq("update all")
|
457
|
-
expect(@ability.unauthorized_message(:foo, Array)).to eq("manage array")
|
458
|
-
expect(@ability.unauthorized_message(:foo, Hash)).to eq("manage all")
|
459
|
-
end
|
460
|
-
|
461
|
-
it "follows aliased actions" do
|
462
|
-
I18n.backend.store_translations :en, :unauthorized => {:modify => {:array => "modify array"}}
|
463
|
-
@ability.alias_action :update, :to => :modify
|
464
|
-
expect(@ability.unauthorized_message(:update, Array)).to eq("modify array")
|
465
|
-
expect(@ability.unauthorized_message(:edit, Array)).to eq("modify array")
|
466
|
-
end
|
467
|
-
|
468
|
-
it "has variables for action and subject" do
|
469
|
-
I18n.backend.store_translations :en, :unauthorized => {:manage => {:all => "%{action} %{subject}"}} # old syntax for now in case testing with old I18n
|
470
|
-
expect(@ability.unauthorized_message(:update, Array)).to eq("update array")
|
471
|
-
expect(@ability.unauthorized_message(:update, ArgumentError)).to eq("update argument error")
|
472
|
-
expect(@ability.unauthorized_message(:edit, 1..3)).to eq("edit range")
|
473
|
-
end
|
474
|
-
end
|
475
|
-
|
476
|
-
describe "#merge" do
|
477
|
-
it "adds the rules from the given ability" do
|
478
|
-
@ability.can :use, :tools
|
479
|
-
(another_ability = double).extend(CanCan::Ability)
|
480
|
-
another_ability.can :use, :search
|
481
|
-
|
482
|
-
@ability.merge(another_ability)
|
483
|
-
expect(@ability.can?(:use, :search)).to be(true)
|
484
|
-
expect(@ability.send(:rules).size).to eq(2)
|
485
|
-
end
|
486
|
-
end
|
487
|
-
end
|
@@ -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
|