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,87 +0,0 @@
1
- module CanCan
2
- module ModelAdapters
3
- class SequelAdapter < AbstractAdapter
4
- def self.for_class?(model_class)
5
- model_class <= Sequel::Model
6
- end
7
-
8
- def self.find(model_class, id)
9
- model_class[id]
10
- end
11
-
12
- def self.override_condition_matching?(subject, name, value)
13
- value.kind_of?(Hash)
14
- end
15
-
16
- def self.matches_condition?(subject, name, value)
17
- obj = subject.send(name)
18
- if obj.nil?
19
- false
20
- else
21
- value.each do |k, v|
22
- if v.kind_of?(Hash)
23
- return false unless self.matches_condition?(obj, k, v)
24
- elsif obj.send(k) != v
25
- return false
26
- end
27
- end
28
- end
29
- end
30
-
31
- def database_records
32
- if @rules.size == 0
33
- @model_class.where('1=0')
34
- else
35
- # only need to process can rules if there are no can rule with empty conditions
36
- rules = @rules.reject { |rule| rule.base_behavior && rule.conditions.empty? }
37
- rules.reject! { |rule| rule.base_behavior } if rules.count < @rules.count
38
-
39
- can_condition_added = false
40
- rules.reverse.inject(@model_class.dataset) do |records, rule|
41
- normalized_conditions = normalize_conditions(rule.conditions)
42
- if rule.base_behavior
43
- if can_condition_added
44
- records.or normalized_conditions
45
- else
46
- can_condition_added = true
47
- records.where normalized_conditions
48
- end
49
- else
50
- records.exclude normalized_conditions
51
- end
52
- end
53
- end
54
- end
55
-
56
- private
57
-
58
- def normalize_conditions(conditions, model_class = @model_class)
59
- return conditions unless conditions.kind_of? Hash
60
- conditions.inject({}) do |result_hash, (name, value)|
61
- if value.kind_of? Hash
62
- value = value.dup
63
- association_class = model_class.association_reflection(name).associated_class
64
- nested = value.inject({}) do |nested, (k, v)|
65
- if v.kind_of?(Hash)
66
- value.delete(k)
67
- nested_class = association_class.association_reflection(k).associated_class
68
- nested[k] = nested_class.where(normalize_conditions(v, association_class))
69
- else
70
- nested[k] = v
71
- end
72
- nested
73
- end
74
- result_hash[name] = association_class.where(nested)
75
- else
76
- result_hash[name] = value
77
- end
78
- result_hash
79
- end
80
- end
81
- end
82
- end
83
- end
84
-
85
- Sequel::Model.class_eval do
86
- include CanCan::ModelAdditions
87
- end
@@ -1,27 +0,0 @@
1
- = CanCan Specs
2
-
3
- == Running the specs
4
-
5
- To run the specs first run the +bundle+ command to install the necessary gems and the +rake+ command to run the specs.
6
-
7
- bundle
8
-
9
- Then run the appraisal command to install all the necessary test sets:
10
-
11
- appraisal install
12
-
13
- You can then run all test sets:
14
-
15
- appraisal rake
16
-
17
- Or individual ones:
18
-
19
- appraisal rails_3.0 rake
20
-
21
- A list of the tests is in the +Appraisal+ file.
22
-
23
- The specs support Ruby 1.8.7+
24
-
25
- == Model Adapters
26
-
27
- The model adapter ENV setting has been removed and replaced with the +Appraisal+ file.
@@ -1,521 +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 "overrides earlier rules with later ones (even if a different exact subject)" do
49
- @ability.cannot :read, Numeric
50
- @ability.can :read, Integer
51
-
52
- expect(@ability.can?(:read, 6)).to be(true)
53
- end
54
-
55
- it "does not pass class with object if :all objects are accepted" do
56
- @ability.can :preview, :all do |object|
57
- expect(object).to eq(123)
58
- @block_called = true
59
- end
60
- @ability.can?(:preview, 123)
61
- expect(@block_called).to be(true)
62
- end
63
-
64
- it "does not call block when only class is passed, only return true" do
65
- @block_called = false
66
- @ability.can :preview, :all do |object|
67
- @block_called = true
68
- end
69
- expect(@ability.can?(:preview, Hash)).to be(true)
70
- expect(@block_called).to be(false)
71
- end
72
-
73
- it "passes only object for global manage actions" do
74
- @ability.can :manage, String do |object|
75
- expect(object).to eq("foo")
76
- @block_called = true
77
- end
78
- expect(@ability.can?(:stuff, "foo")).to be(true)
79
- expect(@block_called).to be(true)
80
- end
81
-
82
- it "makes alias for update or destroy actions to modify action" do
83
- @ability.alias_action :update, :destroy, :to => :modify
84
- @ability.can :modify, :all
85
- expect(@ability.can?(:update, 123)).to be(true)
86
- expect(@ability.can?(:destroy, 123)).to be(true)
87
- end
88
-
89
- it "allows deeply nested aliased actions" do
90
- @ability.alias_action :increment, :to => :sort
91
- @ability.alias_action :sort, :to => :modify
92
- @ability.can :modify, :all
93
- expect(@ability.can?(:increment, 123)).to be(true)
94
- end
95
-
96
- it "raises an Error if alias target is an exist action" do
97
- 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")
98
- end
99
-
100
- it "always calls block with arguments when passing no arguments to can" do
101
- @ability.can do |action, object_class, object|
102
- expect(action).to eq(:foo)
103
- expect(object_class).to eq(123.class)
104
- expect(object).to eq(123)
105
- @block_called = true
106
- end
107
- @ability.can?(:foo, 123)
108
- expect(@block_called).to be(true)
109
- end
110
-
111
- it "passes nil to object when comparing class with can check" do
112
- @ability.can do |action, object_class, object|
113
- expect(action).to eq(:foo)
114
- expect(object_class).to eq(Hash)
115
- expect(object).to be_nil
116
- @block_called = true
117
- end
118
- @ability.can?(:foo, Hash)
119
- expect(@block_called).to be(true)
120
- end
121
-
122
- it "automatically makes alias for index and show into read calls" do
123
- @ability.can :read, :all
124
- expect(@ability.can?(:index, 123)).to be(true)
125
- expect(@ability.can?(:show, 123)).to be(true)
126
- end
127
-
128
- it "automatically makes alias for new and edit into create and update respectively" do
129
- @ability.can :create, :all
130
- @ability.can :update, :all
131
- expect(@ability.can?(:new, 123)).to be(true)
132
- expect(@ability.can?(:edit, 123)).to be(true)
133
- end
134
-
135
- it "does not respond to prepare (now using initialize)" do
136
- expect(@ability).to_not respond_to(:prepare)
137
- end
138
-
139
- it "offers cannot? method which is simply invert of can?" do
140
- expect(@ability.cannot?(:tie, String)).to be(true)
141
- end
142
-
143
- it "is able to specify multiple actions and match any" do
144
- @ability.can [:read, :update], :all
145
- expect(@ability.can?(:read, 123)).to be(true)
146
- expect(@ability.can?(:update, 123)).to be(true)
147
- expect(@ability.can?(:count, 123)).to be(false)
148
- end
149
-
150
- it "is able to specify multiple classes and match any" do
151
- @ability.can :update, [String, Range]
152
- expect(@ability.can?(:update, "foo")).to be(true)
153
- expect(@ability.can?(:update, 1..3)).to be(true)
154
- expect(@ability.can?(:update, 123)).to be(false)
155
- end
156
-
157
- it "checks if there is a permission for any of given subjects" do
158
- @ability.can :update, [String, Range]
159
- expect(@ability.can?(:update, {:any => ["foo", 1..3]})).to be(true)
160
- expect(@ability.can?(:update, {:any => [1..3, "foo"]})).to be(true)
161
- expect(@ability.can?(:update, {:any => [123, "foo"]})).to be(true)
162
- expect(@ability.can?(:update, {:any => [123, 1.0]})).to be(false)
163
- end
164
-
165
- it "lists all permissions" do
166
- @ability.can :manage, :all
167
- @ability.can :learn, Range
168
- @ability.cannot :read, String
169
- @ability.cannot :read, Hash
170
- @ability.cannot :preview, Array
171
-
172
- expected_list = {:can => {:manage => ["all"],
173
- :learn => ["Range"]
174
- },
175
- :cannot => {:read => ["String", "Hash"],
176
- :index => ["String", "Hash"],
177
- :show => ["String", "Hash"],
178
- :preview => ["Array"]
179
- }
180
- }
181
-
182
- expect(@ability.permissions).to eq(expected_list)
183
- end
184
-
185
- it "supports custom objects in the rule" do
186
- @ability.can :read, :stats
187
- expect(@ability.can?(:read, :stats)).to be(true)
188
- expect(@ability.can?(:update, :stats)).to be(false)
189
- expect(@ability.can?(:read, :nonstats)).to be(false)
190
- expect(@ability.can?(:read, {:any => [:stats, :nonstats]})).to be(true)
191
- expect(@ability.can?(:read, {:any => [:nonstats, :neitherstats]})).to be(false)
192
- end
193
-
194
- it "checks ancestors of class" do
195
- @ability.can :read, Numeric
196
- expect(@ability.can?(:read, Integer)).to be(true)
197
- expect(@ability.can?(:read, 1.23)).to be(true)
198
- expect(@ability.can?(:read, "foo")).to be(false)
199
- expect(@ability.can?(:read, {:any => [Integer, String]})).to be(true)
200
- end
201
-
202
- it "supports 'cannot' method to define what user cannot do" do
203
- @ability.can :read, :all
204
- @ability.cannot :read, Integer
205
- expect(@ability.can?(:read, "foo")).to be(true)
206
- expect(@ability.can?(:read, 123)).to be(false)
207
- expect(@ability.can?(:read, {:any => ["foo", "bar"]})).to be(true)
208
- expect(@ability.can?(:read, {:any => [123, "foo"]})).to be(false)
209
- expect(@ability.can?(:read, {:any => [123, 456]})).to be(false)
210
- end
211
-
212
- it "passes to previous rule, if block returns false or nil" do
213
- @ability.can :read, :all
214
- @ability.cannot :read, Integer do |int|
215
- int > 10 ? nil : ( int > 5 )
216
- end
217
-
218
- expect(@ability.can?(:read, "foo")).to be(true)
219
- expect(@ability.can?(:read, 3)).to be(true)
220
- expect(@ability.can?(:read, 8)).to be(false)
221
- expect(@ability.can?(:read, 123)).to be(true)
222
- expect(@ability.can?(:read, {:any => [123, 8]})).to be(true)
223
- expect(@ability.can?(:read, {:any => [8, 9]})).to be(false)
224
- end
225
-
226
- it "always returns `false` for single cannot definition" do
227
- @ability.cannot :read, Integer do |int|
228
- int > 10 ? nil : ( int > 5 )
229
- end
230
- expect(@ability.can?(:read, "foo")).to be(false)
231
- expect(@ability.can?(:read, 3)).to be(false)
232
- expect(@ability.can?(:read, 8)).to be(false)
233
- expect(@ability.can?(:read, 123)).to be(false)
234
- end
235
-
236
- it "passes to previous cannot definition, if block returns false or nil" do
237
- @ability.cannot :read, :all
238
- @ability.can :read, Integer do |int|
239
- int > 10 ? nil : ( int > 5 )
240
- end
241
- expect(@ability.can?(:read, "foo")).to be(false)
242
- expect(@ability.can?(:read, 3)).to be(false)
243
- expect(@ability.can?(:read, 10)).to be(true)
244
- expect(@ability.can?(:read, 123)).to be(false)
245
- end
246
-
247
- it "appends aliased actions" do
248
- @ability.alias_action :update, :to => :modify
249
- @ability.alias_action :destroy, :to => :modify
250
- expect(@ability.aliased_actions[:modify]).to eq([:update, :destroy])
251
- end
252
-
253
- it "clears aliased actions" do
254
- @ability.alias_action :update, :to => :modify
255
- @ability.clear_aliased_actions
256
- expect(@ability.aliased_actions[:modify]).to be_nil
257
- end
258
-
259
- it "passes additional arguments to block from can?" do
260
- @ability.can :read, Integer do |int, x|
261
- int > x
262
- end
263
-
264
- expect(@ability.can?(:read, 2, 1)).to be(true)
265
- expect(@ability.can?(:read, 2, 3)).to be(false)
266
- expect(@ability.can?(:read, {:any => [4, 5]}, 3)).to be(true)
267
- expect(@ability.can?(:read, {:any => [2, 3]}, 3)).to be(false)
268
- end
269
-
270
- it "uses conditions as third parameter and determine abilities from it" do
271
- @ability.can :read, Range, :begin => 1, :end => 3
272
-
273
- expect(@ability.can?(:read, 1..3)).to be(true)
274
- expect(@ability.can?(:read, 1..4)).to be(false)
275
- expect(@ability.can?(:read, Range)).to be(true)
276
- expect(@ability.can?(:read, {:any => [1..3, 1..4]})).to be(true)
277
- expect(@ability.can?(:read, {:any => [1..4, 2..4]})).to be(false)
278
- end
279
-
280
- it "allows an array of options in conditions hash" do
281
- @ability.can :read, Range, :begin => [1, 3, 5]
282
-
283
- expect(@ability.can?(:read, 1..3)).to be(true)
284
- expect(@ability.can?(:read, 2..4)).to be(false)
285
- expect(@ability.can?(:read, 3..5)).to be(true)
286
- expect(@ability.can?(:read, {:any => [2..4, 3..5]})).to be(true)
287
- expect(@ability.can?(:read, {:any => [2..4, 2..5]})).to be(false)
288
- end
289
-
290
- it "allows a range of options in conditions hash" do
291
- @ability.can :read, Range, :begin => 1..3
292
- expect(@ability.can?(:read, 1..10)).to be(true)
293
- expect(@ability.can?(:read, 3..30)).to be(true)
294
- expect(@ability.can?(:read, 4..40)).to be(false)
295
- end
296
-
297
- it "allows nested hashes in conditions hash" do
298
- @ability.can :read, Range, :begin => { :to_i => 5 }
299
- expect(@ability.can?(:read, 5..7)).to be(true)
300
- expect(@ability.can?(:read, 6..8)).to be(false)
301
- end
302
-
303
- it "matches any element passed in to nesting if it's an array (for has_many associations)" do
304
- @ability.can :read, Range, :to_a => { :to_i => 3 }
305
- expect(@ability.can?(:read, 1..5)).to be(true)
306
- expect(@ability.can?(:read, 4..6)).to be(false)
307
- end
308
-
309
- it "accepts a set as a condition value" do
310
- expect(object_with_foo_2 = double(:foo => 2)).to receive(:foo)
311
- expect(object_with_foo_3 = double(:foo => 3)).to receive(:foo)
312
- @ability.can :read, Object, :foo => [1, 2, 5].to_set
313
- expect(@ability.can?(:read, object_with_foo_2)).to be(true)
314
- expect(@ability.can?(:read, object_with_foo_3)).to be(false)
315
- end
316
-
317
- it "does not match subjects return nil for methods that must match nested a nested conditions hash" do
318
- expect(object_with_foo = double(:foo => :bar)).to receive(:foo)
319
- @ability.can :read, Array, :first => { :foo => :bar }
320
- expect(@ability.can?(:read, [object_with_foo])).to be(true)
321
- expect(@ability.can?(:read, [])).to be(false)
322
- end
323
-
324
- it "matches strings but not substrings specified in a conditions hash" do
325
- @ability.can :read, String, :presence => "declassified"
326
- expect(@ability.can?(:read, "declassified")).to be(true)
327
- expect(@ability.can?(:read, "classified")).to be(false)
328
- end
329
-
330
- it "does not stop at cannot definition when comparing class" do
331
- @ability.can :read, Range
332
- @ability.cannot :read, Range, :begin => 1
333
- expect(@ability.can?(:read, 2..5)).to be(true)
334
- expect(@ability.can?(:read, 1..5)).to be(false)
335
- expect(@ability.can?(:read, Range)).to be(true)
336
- end
337
-
338
- it "stops at cannot definition when no hash is present" do
339
- @ability.can :read, :all
340
- @ability.cannot :read, Range
341
- expect(@ability.can?(:read, 1..5)).to be(false)
342
- expect(@ability.can?(:read, Range)).to be(false)
343
- end
344
-
345
- it "allows to check ability for Module" do
346
- module B; end
347
- class A; include B; end
348
- @ability.can :read, B
349
- expect(@ability.can?(:read, A)).to be(true)
350
- expect(@ability.can?(:read, A.new)).to be(true)
351
- end
352
-
353
- it "passes nil to a block for ability on Module when no instance is passed" do
354
- module B; end
355
- class A; include B; end
356
- @ability.can :read, B do |sym|
357
- expect(sym).to be_nil
358
- true
359
- end
360
- expect(@ability.can?(:read, B)).to be(true)
361
- expect(@ability.can?(:read, A)).to be(true)
362
- end
363
-
364
- it "checks permissions through association when passing a hash of subjects" do
365
- @ability.can :read, Range, :string => {:length => 3}
366
-
367
- expect(@ability.can?(:read, "foo" => Range)).to be(true)
368
- expect(@ability.can?(:read, "foobar" => Range)).to be(false)
369
- expect(@ability.can?(:read, 123 => Range)).to be(true)
370
- expect(@ability.can?(:read, {:any => [{"foo" => Range}, {"foobar" => Range}]})).to be(true)
371
- expect(@ability.can?(:read, {:any => [{"food" => Range}, {"foobar" => Range}]})).to be(false)
372
- end
373
-
374
- it "checks permissions correctly when passing a hash of subjects with multiple definitions" do
375
- @ability.can :read, Range, :string => {:length => 4}
376
- @ability.can [:create, :read], Range, :string => {:upcase => 'FOO'}
377
-
378
- expect(@ability.can?(:read, "foo" => Range)).to be(true)
379
- expect(@ability.can?(:read, "foobar" => Range)).to be(false)
380
- expect(@ability.can?(:read, 1234 => Range)).to be(true)
381
- expect(@ability.can?(:read, {:any => [{"foo" => Range}, {"foobar" => Range}]})).to be(true)
382
- expect(@ability.can?(:read, {:any => [{"foo.bar" => Range}, {"foobar" => Range}]})).to be(false)
383
- end
384
-
385
- it "allows to check ability on Hash-like object" do
386
- class Container < Hash; end
387
- @ability.can :read, Container
388
- expect(@ability.can?(:read, Container.new)).to be(true)
389
- end
390
-
391
- it "has initial attributes based on hash conditions of 'new' action" do
392
- @ability.can :manage, Range, :foo => "foo", :hash => {:skip => "hashes"}
393
- @ability.can :create, Range, :bar => 123, :array => %w[skip arrays]
394
- @ability.can :new, Range, :baz => "baz", :range => 1..3
395
- @ability.cannot :new, Range, :ignore => "me"
396
- expect(@ability.attributes_for(:new, Range)).to eq({:foo => "foo", :bar => 123, :baz => "baz"})
397
- end
398
-
399
- it "raises access denied exception if ability us unauthorized to perform a certain action" do
400
- begin
401
- @ability.authorize! :read, :foo, 1, 2, 3, :message => "Access denied!"
402
- rescue CanCan::AccessDenied => e
403
- expect(e.message).to eq("Access denied!")
404
- expect(e.action).to eq(:read)
405
- expect(e.subject).to eq(:foo)
406
- else
407
- fail "Expected CanCan::AccessDenied exception to be raised"
408
- end
409
- end
410
-
411
- it "does not raise access denied exception if ability is authorized to perform an action and return subject" do
412
- @ability.can :read, :foo
413
- expect {
414
- expect(@ability.authorize!(:read, :foo)).to eq(:foo)
415
- }.to_not raise_error
416
- end
417
-
418
- it "knows when block is used in conditions" do
419
- @ability.can :read, :foo
420
- expect(@ability).to_not have_block(:read, :foo)
421
- @ability.can :read, :foo do |foo|
422
- false
423
- end
424
- expect(@ability).to have_block(:read, :foo)
425
- end
426
-
427
- it "knows when raw sql is used in conditions" do
428
- @ability.can :read, :foo
429
- expect(@ability).to_not have_raw_sql(:read, :foo)
430
- @ability.can :read, :foo, 'false'
431
- expect(@ability).to have_raw_sql(:read, :foo)
432
- end
433
-
434
- it "raises access denied exception with default message if not specified" do
435
- begin
436
- @ability.authorize! :read, :foo
437
- rescue CanCan::AccessDenied => e
438
- e.default_message = "Access denied!"
439
- expect(e.message).to eq("Access denied!")
440
- else
441
- fail "Expected CanCan::AccessDenied exception to be raised"
442
- end
443
- end
444
-
445
- it "determines model adapterO class by asking AbstractAdapter" do
446
- adapter_class, model_class = double, double
447
- allow(CanCan::ModelAdapters::AbstractAdapter).to receive(:adapter_class).with(model_class) { adapter_class }
448
- allow(adapter_class).to receive(:new).with(model_class, []) { :adapter_instance }
449
- expect(@ability.model_adapter(model_class, :read)).to eq(:adapter_instance)
450
- end
451
-
452
- it "raises an error when attempting to use a block with a hash condition since it's not likely what they want" do
453
- expect {
454
- @ability.can :read, Array, :published => true do
455
- false
456
- end
457
- }.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.")
458
- end
459
-
460
- describe "unauthorized message" do
461
- after(:each) do
462
- I18n.backend = nil
463
- end
464
-
465
- it "uses action/subject in i18n" do
466
- I18n.backend.store_translations :en, :unauthorized => {:update => {:array => "foo"}}
467
- expect(@ability.unauthorized_message(:update, Array)).to eq("foo")
468
- expect(@ability.unauthorized_message(:update, [1, 2, 3])).to eq("foo")
469
- expect(@ability.unauthorized_message(:update, :missing)).to be_nil
470
- end
471
-
472
- it "uses symbol as subject directly" do
473
- I18n.backend.store_translations :en, :unauthorized => {:has => {:cheezburger => "Nom nom nom. I eated it."}}
474
- expect(@ability.unauthorized_message(:has, :cheezburger)).to eq("Nom nom nom. I eated it.")
475
- end
476
-
477
- it "falls back to 'manage' and 'all'" do
478
- I18n.backend.store_translations :en, :unauthorized => {
479
- :manage => {:all => "manage all", :array => "manage array"},
480
- :update => {:all => "update all", :array => "update array"}
481
- }
482
- expect(@ability.unauthorized_message(:update, Array)).to eq("update array")
483
- expect(@ability.unauthorized_message(:update, Hash)).to eq("update all")
484
- expect(@ability.unauthorized_message(:foo, Array)).to eq("manage array")
485
- expect(@ability.unauthorized_message(:foo, Hash)).to eq("manage all")
486
- end
487
-
488
- it "follows aliased actions" do
489
- I18n.backend.store_translations :en, :unauthorized => {:modify => {:array => "modify array"}}
490
- @ability.alias_action :update, :to => :modify
491
- expect(@ability.unauthorized_message(:update, Array)).to eq("modify array")
492
- expect(@ability.unauthorized_message(:edit, Array)).to eq("modify array")
493
- end
494
-
495
- it "has variables for action and subject" do
496
- I18n.backend.store_translations :en, :unauthorized => {:manage => {:all => "%{action} %{subject}"}} # old syntax for now in case testing with old I18n
497
- expect(@ability.unauthorized_message(:update, Array)).to eq("update array")
498
- expect(@ability.unauthorized_message(:update, ArgumentError)).to eq("update argument error")
499
- expect(@ability.unauthorized_message(:edit, 1..3)).to eq("edit range")
500
- end
501
- end
502
-
503
- describe "#merge" do
504
- it "adds the rules from the given ability" do
505
- @ability.can :use, :tools
506
- (another_ability = double).extend(CanCan::Ability)
507
- another_ability.can :use, :search
508
-
509
- @ability.merge(another_ability)
510
- expect(@ability.can?(:use, :search)).to be(true)
511
- expect(@ability.send(:rules).size).to eq(2)
512
- end
513
-
514
- it "can add an empty ability" do
515
- (another_ability = double).extend(CanCan::Ability)
516
-
517
- @ability.merge(another_ability)
518
- expect(@ability.send(:rules).size).to eq(0)
519
- end
520
- end
521
- end