cancancan 1.13.1 → 3.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +5 -5
  2. data/cancancan.gemspec +18 -18
  3. data/init.rb +2 -0
  4. data/lib/cancan.rb +9 -11
  5. data/lib/cancan/ability.rb +93 -194
  6. data/lib/cancan/ability/actions.rb +93 -0
  7. data/lib/cancan/ability/rules.rb +93 -0
  8. data/lib/cancan/ability/strong_parameter_support.rb +41 -0
  9. data/lib/cancan/conditions_matcher.rb +106 -0
  10. data/lib/cancan/controller_additions.rb +38 -41
  11. data/lib/cancan/controller_resource.rb +52 -211
  12. data/lib/cancan/controller_resource_builder.rb +26 -0
  13. data/lib/cancan/controller_resource_finder.rb +42 -0
  14. data/lib/cancan/controller_resource_loader.rb +120 -0
  15. data/lib/cancan/controller_resource_name_finder.rb +23 -0
  16. data/lib/cancan/controller_resource_sanitizer.rb +32 -0
  17. data/lib/cancan/exceptions.rb +17 -5
  18. data/lib/cancan/matchers.rb +12 -3
  19. data/lib/cancan/model_adapters/abstract_adapter.rb +10 -8
  20. data/lib/cancan/model_adapters/active_record_4_adapter.rb +39 -13
  21. data/lib/cancan/model_adapters/active_record_5_adapter.rb +68 -0
  22. data/lib/cancan/model_adapters/active_record_adapter.rb +77 -82
  23. data/lib/cancan/model_adapters/conditions_extractor.rb +75 -0
  24. data/lib/cancan/model_adapters/conditions_normalizer.rb +49 -0
  25. data/lib/cancan/model_adapters/default_adapter.rb +2 -0
  26. data/lib/cancan/model_additions.rb +2 -1
  27. data/lib/cancan/parameter_validators.rb +9 -0
  28. data/lib/cancan/relevant.rb +29 -0
  29. data/lib/cancan/rule.rb +76 -105
  30. data/lib/cancan/rules_compressor.rb +23 -0
  31. data/lib/cancan/unauthorized_message_resolver.rb +24 -0
  32. data/lib/cancan/version.rb +3 -1
  33. data/lib/cancancan.rb +2 -0
  34. data/lib/generators/cancan/ability/ability_generator.rb +4 -2
  35. data/lib/generators/cancan/ability/templates/ability.rb +2 -0
  36. metadata +66 -56
  37. data/.gitignore +0 -15
  38. data/.rspec +0 -1
  39. data/.travis.yml +0 -28
  40. data/Appraisals +0 -81
  41. data/CHANGELOG.rdoc +0 -518
  42. data/CONTRIBUTING.md +0 -23
  43. data/Gemfile +0 -3
  44. data/LICENSE +0 -22
  45. data/README.md +0 -214
  46. data/Rakefile +0 -9
  47. data/gemfiles/activerecord_3.2.gemfile +0 -16
  48. data/gemfiles/activerecord_4.0.gemfile +0 -17
  49. data/gemfiles/activerecord_4.1.gemfile +0 -17
  50. data/gemfiles/activerecord_4.2.gemfile +0 -18
  51. data/gemfiles/mongoid_2.x.gemfile +0 -16
  52. data/gemfiles/sequel_3.x.gemfile +0 -16
  53. data/lib/cancan/inherited_resource.rb +0 -20
  54. data/lib/cancan/model_adapters/active_record_3_adapter.rb +0 -16
  55. data/lib/cancan/model_adapters/mongoid_adapter.rb +0 -54
  56. data/lib/cancan/model_adapters/sequel_adapter.rb +0 -87
  57. data/spec/README.rdoc +0 -27
  58. data/spec/cancan/ability_spec.rb +0 -521
  59. data/spec/cancan/controller_additions_spec.rb +0 -141
  60. data/spec/cancan/controller_resource_spec.rb +0 -632
  61. data/spec/cancan/exceptions_spec.rb +0 -58
  62. data/spec/cancan/inherited_resource_spec.rb +0 -71
  63. data/spec/cancan/matchers_spec.rb +0 -29
  64. data/spec/cancan/model_adapters/active_record_4_adapter_spec.rb +0 -85
  65. data/spec/cancan/model_adapters/active_record_adapter_spec.rb +0 -384
  66. data/spec/cancan/model_adapters/default_adapter_spec.rb +0 -7
  67. data/spec/cancan/model_adapters/mongoid_adapter_spec.rb +0 -227
  68. data/spec/cancan/model_adapters/sequel_adapter_spec.rb +0 -132
  69. data/spec/cancan/rule_spec.rb +0 -52
  70. data/spec/matchers.rb +0 -13
  71. data/spec/spec.opts +0 -2
  72. data/spec/spec_helper.rb +0 -27
  73. data/spec/support/ability.rb +0 -7
@@ -1,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