cancan 1.3.4 → 1.4.0.beta1
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.
- data/CHANGELOG.rdoc +19 -0
- data/README.rdoc +1 -1
- data/Rakefile +1 -1
- data/lib/cancan/ability.rb +80 -31
- data/lib/cancan/can_definition.rb +33 -11
- data/lib/cancan/controller_additions.rb +59 -6
- data/lib/cancan/controller_resource.rb +18 -6
- data/lib/cancan/exceptions.rb +5 -1
- data/spec/cancan/ability_spec.rb +128 -59
- data/spec/cancan/active_record_additions_spec.rb +1 -1
- data/spec/cancan/can_definition_spec.rb +1 -0
- data/spec/cancan/controller_additions_spec.rb +25 -26
- data/spec/cancan/controller_resource_spec.rb +92 -83
- data/spec/cancan/query_spec.rb +48 -48
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +12 -2
- metadata +5 -4
data/lib/cancan/exceptions.rb
CHANGED
@@ -5,6 +5,9 @@ module CanCan
|
|
5
5
|
# Raised when removed code is called, an alternative solution is provided in message.
|
6
6
|
class ImplementationRemoved < Error; end
|
7
7
|
|
8
|
+
# Raised when using check_authorization without calling authorized!
|
9
|
+
class AuthorizationNotPerformed < Error; end
|
10
|
+
|
8
11
|
# This error is raised when a user isn't allowed to access a given controller action.
|
9
12
|
# This usually happens within a call to ControllerAdditions#authorize! but can be
|
10
13
|
# raised manually.
|
@@ -24,7 +27,8 @@ module CanCan
|
|
24
27
|
# exception.default_message = "Default error message"
|
25
28
|
# exception.message # => "Default error message"
|
26
29
|
#
|
27
|
-
# See ControllerAdditions#authorized! for more information on rescuing from this exception
|
30
|
+
# See ControllerAdditions#authorized! for more information on rescuing from this exception
|
31
|
+
# and customizing the message using I18n.
|
28
32
|
class AccessDenied < Error
|
29
33
|
attr_reader :action, :subject
|
30
34
|
attr_writer :default_message
|
data/spec/cancan/ability_spec.rb
CHANGED
@@ -38,9 +38,8 @@ describe CanCan::Ability do
|
|
38
38
|
@ability.can?(:read, 6).should be_false
|
39
39
|
end
|
40
40
|
|
41
|
-
it "should pass class with object if :all objects are accepted" do
|
42
|
-
@ability.can :preview, :all do |
|
43
|
-
object_class.should == Fixnum
|
41
|
+
it "should not pass class with object if :all objects are accepted" do
|
42
|
+
@ability.can :preview, :all do |object|
|
44
43
|
object.should == 123
|
45
44
|
@block_called = true
|
46
45
|
end
|
@@ -48,23 +47,21 @@ describe CanCan::Ability do
|
|
48
47
|
@block_called.should be_true
|
49
48
|
end
|
50
49
|
|
51
|
-
it "should
|
52
|
-
@
|
53
|
-
|
54
|
-
object.should be_nil
|
50
|
+
it "should not call block when only class is passed, only return true" do
|
51
|
+
@block_called = false
|
52
|
+
@ability.can :preview, :all do |object|
|
55
53
|
@block_called = true
|
56
54
|
end
|
57
|
-
@ability.can?(:preview, Hash)
|
58
|
-
@block_called.should
|
55
|
+
@ability.can?(:preview, Hash).should be_true
|
56
|
+
@block_called.should be_false
|
59
57
|
end
|
60
58
|
|
61
|
-
it "should pass
|
62
|
-
@ability.can :manage,
|
63
|
-
|
64
|
-
object.should == [1, 2]
|
59
|
+
it "should pass only object for global manage actions" do
|
60
|
+
@ability.can :manage, String do |object|
|
61
|
+
object.should == "foo"
|
65
62
|
@block_called = true
|
66
63
|
end
|
67
|
-
@ability.can?(:stuff,
|
64
|
+
@ability.can?(:stuff, "foo").should
|
68
65
|
@block_called.should be_true
|
69
66
|
end
|
70
67
|
|
@@ -82,10 +79,10 @@ describe CanCan::Ability do
|
|
82
79
|
@ability.can?(:increment, 123).should be_true
|
83
80
|
end
|
84
81
|
|
85
|
-
it "should
|
86
|
-
@ability.can
|
82
|
+
it "should always call block with arguments when passing no arguments to can" do
|
83
|
+
@ability.can do |action, object_class, object|
|
87
84
|
action.should == :foo
|
88
|
-
object_class.should ==
|
85
|
+
object_class.should == 123.class
|
89
86
|
object.should == 123
|
90
87
|
@block_called = true
|
91
88
|
end
|
@@ -93,6 +90,17 @@ describe CanCan::Ability do
|
|
93
90
|
@block_called.should be_true
|
94
91
|
end
|
95
92
|
|
93
|
+
it "should pass nil to object when comparing class with can check" do
|
94
|
+
@ability.can do |action, object_class, object|
|
95
|
+
action.should == :foo
|
96
|
+
object_class.should == Hash
|
97
|
+
object.should be_nil
|
98
|
+
@block_called = true
|
99
|
+
end
|
100
|
+
@ability.can?(:foo, Hash)
|
101
|
+
@block_called.should be_true
|
102
|
+
end
|
103
|
+
|
96
104
|
it "should automatically alias index and show into read calls" do
|
97
105
|
@ability.can :read, :all
|
98
106
|
@ability.can?(:index, 123).should be_true
|
@@ -122,9 +130,9 @@ describe CanCan::Ability do
|
|
122
130
|
end
|
123
131
|
|
124
132
|
it "should be able to specify multiple classes and match any" do
|
125
|
-
@ability.can :update, [String,
|
133
|
+
@ability.can :update, [String, Range]
|
126
134
|
@ability.can?(:update, "foo").should be_true
|
127
|
-
@ability.can?(:update,
|
135
|
+
@ability.can?(:update, 1..3).should be_true
|
128
136
|
@ability.can?(:update, 123).should be_false
|
129
137
|
end
|
130
138
|
|
@@ -149,18 +157,7 @@ describe CanCan::Ability do
|
|
149
157
|
@ability.can?(:read, 123).should be_false
|
150
158
|
end
|
151
159
|
|
152
|
-
it "should support block on 'cannot' method" do
|
153
|
-
@ability.can :read, :all
|
154
|
-
@ability.cannot :read, Integer do |int|
|
155
|
-
int > 5
|
156
|
-
end
|
157
|
-
@ability.can?(:read, "foo").should be_true
|
158
|
-
@ability.can?(:read, 3).should be_true
|
159
|
-
@ability.can?(:read, 123).should be_false
|
160
|
-
end
|
161
|
-
|
162
160
|
it "should pass to previous can definition, if block returns false or nil" do
|
163
|
-
#same as previous
|
164
161
|
@ability.can :read, :all
|
165
162
|
@ability.cannot :read, Integer do |int|
|
166
163
|
int > 10 ? nil : ( int > 5 )
|
@@ -169,7 +166,6 @@ describe CanCan::Ability do
|
|
169
166
|
@ability.can?(:read, 3).should be_true
|
170
167
|
@ability.can?(:read, 8).should be_false
|
171
168
|
@ability.can?(:read, 123).should be_true
|
172
|
-
|
173
169
|
end
|
174
170
|
|
175
171
|
it "should always return `false` for single cannot definition" do
|
@@ -214,49 +210,122 @@ describe CanCan::Ability do
|
|
214
210
|
end
|
215
211
|
|
216
212
|
it "should use conditions as third parameter and determine abilities from it" do
|
217
|
-
@ability.can :read,
|
218
|
-
@ability.can?(:read,
|
219
|
-
@ability.can?(:read,
|
220
|
-
@ability.can?(:read,
|
213
|
+
@ability.can :read, Range, :begin => 1, :end => 3
|
214
|
+
@ability.can?(:read, 1..3).should be_true
|
215
|
+
@ability.can?(:read, 1..4).should be_false
|
216
|
+
@ability.can?(:read, Range).should be_true
|
221
217
|
end
|
222
218
|
|
223
219
|
it "should allow an array of options in conditions hash" do
|
224
|
-
@ability.can :read,
|
225
|
-
@ability.can?(:read,
|
226
|
-
@ability.can?(:read,
|
227
|
-
@ability.can?(:read,
|
220
|
+
@ability.can :read, Range, :begin => [1, 3, 5]
|
221
|
+
@ability.can?(:read, 1..3).should be_true
|
222
|
+
@ability.can?(:read, 2..4).should be_false
|
223
|
+
@ability.can?(:read, 3..5).should be_true
|
228
224
|
end
|
229
225
|
|
230
226
|
it "should allow a range of options in conditions hash" do
|
231
|
-
@ability.can :read,
|
232
|
-
@ability.can?(:read,
|
233
|
-
@ability.can?(:read,
|
234
|
-
@ability.can?(:read,
|
227
|
+
@ability.can :read, Range, :begin => 1..3
|
228
|
+
@ability.can?(:read, 1..10).should be_true
|
229
|
+
@ability.can?(:read, 3..30).should be_true
|
230
|
+
@ability.can?(:read, 4..40).should be_false
|
235
231
|
end
|
236
232
|
|
237
233
|
it "should allow nested hashes in conditions hash" do
|
238
|
-
@ability.can :read,
|
239
|
-
@ability.can?(:read,
|
240
|
-
@ability.can?(:read,
|
234
|
+
@ability.can :read, Range, :begin => { :to_i => 5 }
|
235
|
+
@ability.can?(:read, 5..7).should be_true
|
236
|
+
@ability.can?(:read, 6..8).should be_false
|
241
237
|
end
|
242
238
|
|
243
|
-
it "should
|
244
|
-
@ability.can :read,
|
245
|
-
@ability.can?(:read,
|
246
|
-
@ability.can?(:read,
|
239
|
+
it "should match any element passed in to nesting if it's an array (for has_many associations)" do
|
240
|
+
@ability.can :read, Range, :to_a => { :to_i => 3 }
|
241
|
+
@ability.can?(:read, 1..5).should be_true
|
242
|
+
@ability.can?(:read, 4..6).should be_false
|
247
243
|
end
|
248
244
|
|
249
245
|
it "should not stop at cannot definition when comparing class" do
|
250
|
-
@ability.can :read,
|
251
|
-
@ability.cannot :read,
|
252
|
-
@ability.can?(:read,
|
253
|
-
@ability.can?(:read,
|
254
|
-
@ability.can?(:read,
|
246
|
+
@ability.can :read, Range
|
247
|
+
@ability.cannot :read, Range, :begin => 1
|
248
|
+
@ability.can?(:read, 2..5).should be_true
|
249
|
+
@ability.can?(:read, 1..5).should be_false
|
250
|
+
@ability.can?(:read, Range).should be_true
|
251
|
+
end
|
252
|
+
|
253
|
+
it "passing a hash of subjects should check permissions through association" do
|
254
|
+
@ability.can :read, Range, :string => {:length => 3}
|
255
|
+
@ability.can?(:read, "foo" => Range).should be_true
|
256
|
+
@ability.can?(:read, "foobar" => Range).should be_false
|
257
|
+
@ability.can?(:read, 123 => Range).should be_true
|
258
|
+
end
|
259
|
+
|
260
|
+
it "should have initial attributes based on hash conditions of 'new' action" do
|
261
|
+
@ability.can :manage, Range, :foo => "foo", :hash => {:skip => "hashes"}
|
262
|
+
@ability.can :create, Range, :bar => 123, :array => %w[skip arrays]
|
263
|
+
@ability.can :new, Range, :baz => "baz", :range => 1..3
|
264
|
+
@ability.cannot :new, Range, :ignore => "me"
|
265
|
+
@ability.attributes_for(:new, Range).should == {:foo => "foo", :bar => 123, :baz => "baz"}
|
266
|
+
end
|
267
|
+
|
268
|
+
it "should raise access denied exception if ability us unauthorized to perform a certain action" do
|
269
|
+
begin
|
270
|
+
@ability.authorize! :read, :foo, 1, 2, 3, :message => "Access denied!"
|
271
|
+
rescue CanCan::AccessDenied => e
|
272
|
+
e.message.should == "Access denied!"
|
273
|
+
e.action.should == :read
|
274
|
+
e.subject.should == :foo
|
275
|
+
else
|
276
|
+
fail "Expected CanCan::AccessDenied exception to be raised"
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
it "should not raise access denied exception if ability is authorized to perform an action" do
|
281
|
+
@ability.can :read, :foo
|
282
|
+
lambda { @ability.authorize!(:read, :foo) }.should_not raise_error
|
255
283
|
end
|
256
284
|
|
257
|
-
it "should
|
258
|
-
|
259
|
-
@ability.
|
260
|
-
|
285
|
+
it "should raise access denied exception with default message if not specified" do
|
286
|
+
begin
|
287
|
+
@ability.authorize! :read, :foo
|
288
|
+
rescue CanCan::AccessDenied => e
|
289
|
+
e.default_message = "Access denied!"
|
290
|
+
e.message.should == "Access denied!"
|
291
|
+
else
|
292
|
+
fail "Expected CanCan::AccessDenied exception to be raised"
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
describe "unauthorized message" do
|
297
|
+
after(:each) do
|
298
|
+
I18n.backend = nil
|
299
|
+
end
|
300
|
+
|
301
|
+
it "should use action/subject in i18n" do
|
302
|
+
I18n.backend.store_translations :en, :unauthorized => {:update => {:array => "foo"}}
|
303
|
+
@ability.unauthorized_message(:update, Array).should == "foo"
|
304
|
+
@ability.unauthorized_message(:update, [1, 2, 3]).should == "foo"
|
305
|
+
@ability.unauthorized_message(:update, :missing).should be_nil
|
306
|
+
end
|
307
|
+
|
308
|
+
it "should use symbol as subject directly" do
|
309
|
+
I18n.backend.store_translations :en, :unauthorized => {:has => {:cheezburger => "Nom nom nom. I eated it."}}
|
310
|
+
@ability.unauthorized_message(:has, :cheezburger).should == "Nom nom nom. I eated it."
|
311
|
+
end
|
312
|
+
|
313
|
+
it "should fall back to 'manage' and 'all'" do
|
314
|
+
I18n.backend.store_translations :en, :unauthorized => {
|
315
|
+
:manage => {:all => "manage all", :array => "manage array"},
|
316
|
+
:update => {:all => "update all", :array => "update array"}
|
317
|
+
}
|
318
|
+
@ability.unauthorized_message(:update, Array).should == "update array"
|
319
|
+
@ability.unauthorized_message(:update, Hash).should == "update all"
|
320
|
+
@ability.unauthorized_message(:foo, Array).should == "manage array"
|
321
|
+
@ability.unauthorized_message(:foo, Hash).should == "manage all"
|
322
|
+
end
|
323
|
+
|
324
|
+
it "should follow aliased actions" do
|
325
|
+
I18n.backend.store_translations :en, :unauthorized => {:modify => {:array => "modify array"}}
|
326
|
+
@ability.alias_action :update, :to => :modify
|
327
|
+
@ability.unauthorized_message(:update, Array).should == "modify array"
|
328
|
+
@ability.unauthorized_message(:edit, Array).should == "modify array"
|
329
|
+
end
|
261
330
|
end
|
262
331
|
end
|
@@ -2,7 +2,7 @@ require "spec_helper"
|
|
2
2
|
|
3
3
|
describe CanCan::ActiveRecordAdditions do
|
4
4
|
before(:each) do
|
5
|
-
@model_class = Class.new(
|
5
|
+
@model_class = Class.new(Project)
|
6
6
|
stub(@model_class).scoped { :scoped_stub }
|
7
7
|
@model_class.send(:include, CanCan::ActiveRecordAdditions)
|
8
8
|
@ability = Object.new
|
@@ -14,32 +14,10 @@ describe CanCan::ControllerAdditions do
|
|
14
14
|
lambda { @controller.unauthorized! }.should raise_error(CanCan::ImplementationRemoved)
|
15
15
|
end
|
16
16
|
|
17
|
-
it "should
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
e.message.should == "Access denied!"
|
22
|
-
e.action.should == :read
|
23
|
-
e.subject.should == :foo
|
24
|
-
else
|
25
|
-
fail "Expected CanCan::AccessDenied exception to be raised"
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
it "should not raise access denied exception if ability is authorized to perform an action" do
|
30
|
-
@controller.current_ability.can :read, :foo
|
31
|
-
lambda { @controller.authorize!(:read, :foo) }.should_not raise_error
|
32
|
-
end
|
33
|
-
|
34
|
-
it "should raise access denied exception with default message if not specified" do
|
35
|
-
begin
|
36
|
-
@controller.authorize! :read, :foo
|
37
|
-
rescue CanCan::AccessDenied => e
|
38
|
-
e.default_message = "Access denied!"
|
39
|
-
e.message.should == "Access denied!"
|
40
|
-
else
|
41
|
-
fail "Expected CanCan::AccessDenied exception to be raised"
|
42
|
-
end
|
17
|
+
it "authorize! should assign @_authorized instance variable and pass args to current ability" do
|
18
|
+
mock(@controller.current_ability).authorize!(:foo, :bar)
|
19
|
+
@controller.authorize!(:foo, :bar)
|
20
|
+
@controller.instance_variable_get(:@_authorized).should be_true
|
43
21
|
end
|
44
22
|
|
45
23
|
it "should have a current_ability method which generates an ability for the current user" do
|
@@ -75,4 +53,25 @@ describe CanCan::ControllerAdditions do
|
|
75
53
|
mock(@controller_class).before_filter(:only => [:show, :index]) { |options, block| block.call(@controller) }
|
76
54
|
@controller_class.load_resource :foo => :bar, :only => [:show, :index]
|
77
55
|
end
|
56
|
+
|
57
|
+
it "skip_authorization should set up a before filter which sets @_authorized to true" do
|
58
|
+
mock(@controller_class).before_filter(:filter_options) { |options, block| block.call(@controller) }
|
59
|
+
@controller_class.skip_authorization(:filter_options)
|
60
|
+
@controller.instance_variable_get(:@_authorized).should be_true
|
61
|
+
end
|
62
|
+
|
63
|
+
it "check_authorization should trigger AuthorizationNotPerformed in after filter" do
|
64
|
+
mock(@controller_class).after_filter(:some_options) { |options, block| block.call(@controller) }
|
65
|
+
lambda {
|
66
|
+
@controller_class.check_authorization(:some_options)
|
67
|
+
}.should raise_error(CanCan::AuthorizationNotPerformed)
|
68
|
+
end
|
69
|
+
|
70
|
+
it "check_authorization should not raise error when @_authorized is set" do
|
71
|
+
@controller.instance_variable_set(:@_authorized, true)
|
72
|
+
mock(@controller_class).after_filter(:some_options) { |options, block| block.call(@controller) }
|
73
|
+
lambda {
|
74
|
+
@controller_class.check_authorization(:some_options)
|
75
|
+
}.should_not raise_error(CanCan::AuthorizationNotPerformed)
|
76
|
+
end
|
78
77
|
end
|
@@ -2,77 +2,85 @@ require "spec_helper"
|
|
2
2
|
|
3
3
|
describe CanCan::ControllerResource do
|
4
4
|
before(:each) do
|
5
|
-
@params = HashWithIndifferentAccess.new(:controller => "
|
5
|
+
@params = HashWithIndifferentAccess.new(:controller => "projects")
|
6
6
|
@controller = Object.new # simple stub for now
|
7
7
|
stub(@controller).params { @params }
|
8
|
+
stub(@controller).current_ability.stub!.attributes_for { {} }
|
8
9
|
end
|
9
10
|
|
10
11
|
it "should load the resource into an instance variable if params[:id] is specified" do
|
11
12
|
@params.merge!(:action => "show", :id => 123)
|
12
|
-
stub(
|
13
|
+
stub(Project).find(123) { :some_project }
|
13
14
|
resource = CanCan::ControllerResource.new(@controller)
|
14
15
|
resource.load_resource
|
15
|
-
@controller.instance_variable_get(:@
|
16
|
+
@controller.instance_variable_get(:@project).should == :some_project
|
16
17
|
end
|
17
18
|
|
18
19
|
it "should not load resource into an instance variable if already set" do
|
19
20
|
@params.merge!(:action => "show", :id => 123)
|
20
|
-
@controller.instance_variable_set(:@
|
21
|
+
@controller.instance_variable_set(:@project, :some_project)
|
21
22
|
resource = CanCan::ControllerResource.new(@controller)
|
22
23
|
resource.load_resource
|
23
|
-
@controller.instance_variable_get(:@
|
24
|
+
@controller.instance_variable_get(:@project).should == :some_project
|
24
25
|
end
|
25
26
|
|
26
27
|
it "should properly load resource for namespaced controller" do
|
27
|
-
@params.merge!(:controller => "admin/
|
28
|
-
stub(
|
28
|
+
@params.merge!(:controller => "admin/projects", :action => "show", :id => 123)
|
29
|
+
stub(Project).find(123) { :some_project }
|
29
30
|
resource = CanCan::ControllerResource.new(@controller)
|
30
31
|
resource.load_resource
|
31
|
-
@controller.instance_variable_get(:@
|
32
|
+
@controller.instance_variable_get(:@project).should == :some_project
|
32
33
|
end
|
33
34
|
|
34
35
|
it "should properly load resource for namespaced controller when using '::' for namespace" do
|
35
|
-
@params.merge!(:controller => "Admin::
|
36
|
-
stub(
|
36
|
+
@params.merge!(:controller => "Admin::ProjectsController", :action => "show", :id => 123)
|
37
|
+
stub(Project).find(123) { :some_project }
|
37
38
|
resource = CanCan::ControllerResource.new(@controller)
|
38
39
|
resource.load_resource
|
39
|
-
@controller.instance_variable_get(:@
|
40
|
+
@controller.instance_variable_get(:@project).should == :some_project
|
40
41
|
end
|
41
42
|
|
42
43
|
it "should build a new resource with hash if params[:id] is not specified" do
|
43
|
-
@params.merge!(:action => "create", :
|
44
|
-
stub(Ability).new("foo" => "bar") { :some_resource }
|
44
|
+
@params.merge!(:action => "create", :project => {:name => "foobar"})
|
45
45
|
resource = CanCan::ControllerResource.new(@controller)
|
46
46
|
resource.load_resource
|
47
|
-
@controller.instance_variable_get(:@
|
47
|
+
@controller.instance_variable_get(:@project).name.should == "foobar"
|
48
48
|
end
|
49
49
|
|
50
|
-
it "should build a new resource with
|
51
|
-
@params
|
52
|
-
|
50
|
+
it "should build a new resource with attributes from current ability" do
|
51
|
+
@params.merge!(:action => "new")
|
52
|
+
stub(@controller).current_ability.stub!.attributes_for(:new, Project) { {:name => "from conditions"} }
|
53
53
|
resource = CanCan::ControllerResource.new(@controller)
|
54
54
|
resource.load_resource
|
55
|
-
@controller.instance_variable_get(:@
|
55
|
+
@controller.instance_variable_get(:@project).name.should == "from conditions"
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should override initial attributes with params" do
|
59
|
+
@params.merge!(:action => "new", :project => {:name => "from params"})
|
60
|
+
stub(@controller).current_ability.stub!.attributes_for(:new, Project) { {:name => "foobar"} }
|
61
|
+
resource = CanCan::ControllerResource.new(@controller)
|
62
|
+
resource.load_resource
|
63
|
+
@controller.instance_variable_get(:@project).name.should == "from params"
|
56
64
|
end
|
57
65
|
|
58
66
|
it "should not build a resource when on index action" do
|
59
67
|
@params[:action] = "index"
|
60
68
|
resource = CanCan::ControllerResource.new(@controller)
|
61
69
|
resource.load_resource
|
62
|
-
@controller.instance_variable_get(:@
|
70
|
+
@controller.instance_variable_get(:@project).should be_nil
|
63
71
|
end
|
64
72
|
|
65
73
|
it "should perform authorization using controller action and loaded model" do
|
66
74
|
@params[:action] = "show"
|
67
|
-
@controller.instance_variable_set(:@
|
68
|
-
stub(@controller).authorize!(:show, :
|
75
|
+
@controller.instance_variable_set(:@project, :some_project)
|
76
|
+
stub(@controller).authorize!(:show, :some_project) { raise CanCan::AccessDenied }
|
69
77
|
resource = CanCan::ControllerResource.new(@controller)
|
70
78
|
lambda { resource.authorize_resource }.should raise_error(CanCan::AccessDenied)
|
71
79
|
end
|
72
80
|
|
73
81
|
it "should perform authorization using controller action and non loaded model" do
|
74
82
|
@params[:action] = "show"
|
75
|
-
stub(@controller).authorize!(:show,
|
83
|
+
stub(@controller).authorize!(:show, Project) { raise CanCan::AccessDenied }
|
76
84
|
resource = CanCan::ControllerResource.new(@controller)
|
77
85
|
lambda { resource.authorize_resource }.should raise_error(CanCan::AccessDenied)
|
78
86
|
end
|
@@ -89,146 +97,147 @@ describe CanCan::ControllerResource do
|
|
89
97
|
@params[:action] = "sort"
|
90
98
|
resource = CanCan::ControllerResource.new(@controller, :collection => [:sort, :list])
|
91
99
|
resource.load_resource
|
92
|
-
@controller.instance_variable_get(:@
|
100
|
+
@controller.instance_variable_get(:@project).should be_nil
|
93
101
|
end
|
94
102
|
|
95
103
|
it "should build a resource when on custom new action even when params[:id] exists" do
|
96
104
|
@params.merge!(:action => "build", :id => 123)
|
97
|
-
stub(
|
105
|
+
stub(Project).new { :some_project }
|
98
106
|
resource = CanCan::ControllerResource.new(@controller, :new => :build)
|
99
107
|
resource.load_resource
|
100
|
-
@controller.instance_variable_get(:@
|
108
|
+
@controller.instance_variable_get(:@project).should == :some_project
|
101
109
|
end
|
102
110
|
|
103
111
|
it "should not try to load resource for other action if params[:id] is undefined" do
|
104
112
|
@params[:action] = "list"
|
105
113
|
resource = CanCan::ControllerResource.new(@controller)
|
106
114
|
resource.load_resource
|
107
|
-
@controller.instance_variable_get(:@
|
115
|
+
@controller.instance_variable_get(:@project).should be_nil
|
108
116
|
end
|
109
117
|
|
110
118
|
it "should be a parent resource when name is provided which doesn't match controller" do
|
111
|
-
resource = CanCan::ControllerResource.new(@controller, :
|
119
|
+
resource = CanCan::ControllerResource.new(@controller, :category)
|
112
120
|
resource.should be_parent
|
113
121
|
end
|
114
122
|
|
115
123
|
it "should not be a parent resource when name is provided which matches controller" do
|
116
|
-
resource = CanCan::ControllerResource.new(@controller, :
|
124
|
+
resource = CanCan::ControllerResource.new(@controller, :project)
|
117
125
|
resource.should_not be_parent
|
118
126
|
end
|
119
127
|
|
120
128
|
it "should be parent if specified in options" do
|
121
|
-
resource = CanCan::ControllerResource.new(@controller, :
|
129
|
+
resource = CanCan::ControllerResource.new(@controller, :project, {:parent => true})
|
122
130
|
resource.should be_parent
|
123
131
|
end
|
124
132
|
|
125
133
|
it "should not be parent if specified in options" do
|
126
|
-
resource = CanCan::ControllerResource.new(@controller, :
|
134
|
+
resource = CanCan::ControllerResource.new(@controller, :category, {:parent => false})
|
127
135
|
resource.should_not be_parent
|
128
136
|
end
|
129
137
|
|
130
|
-
it "should load parent resource through proper id parameter
|
131
|
-
@params.merge!(:action => "index", :
|
132
|
-
stub(
|
133
|
-
resource = CanCan::ControllerResource.new(@controller, :
|
134
|
-
resource.load_resource
|
135
|
-
@controller.instance_variable_get(:@person).should == :some_person
|
136
|
-
end
|
137
|
-
|
138
|
-
it "should load parent resource for collection action" do
|
139
|
-
@params.merge!(:action => "index", :person_id => 456)
|
140
|
-
stub(Person).find(456) { :some_person }
|
141
|
-
resource = CanCan::ControllerResource.new(@controller, :person)
|
138
|
+
it "should load parent resource through proper id parameter" do
|
139
|
+
@params.merge!(:action => "index", :project_id => 123)
|
140
|
+
stub(Project).find(123) { :some_project }
|
141
|
+
resource = CanCan::ControllerResource.new(@controller, :project, :parent => true)
|
142
142
|
resource.load_resource
|
143
|
-
@controller.instance_variable_get(:@
|
143
|
+
@controller.instance_variable_get(:@project).should == :some_project
|
144
144
|
end
|
145
145
|
|
146
146
|
it "should load resource through the association of another parent resource" do
|
147
147
|
@params.merge!(:action => "show", :id => 123)
|
148
|
-
|
149
|
-
@controller.instance_variable_set(:@
|
150
|
-
stub(
|
151
|
-
resource = CanCan::ControllerResource.new(@controller, :through => :
|
148
|
+
category = Object.new
|
149
|
+
@controller.instance_variable_set(:@category, category)
|
150
|
+
stub(category).projects.stub!.find(123) { :some_project }
|
151
|
+
resource = CanCan::ControllerResource.new(@controller, :through => :category)
|
152
152
|
resource.load_resource
|
153
|
-
@controller.instance_variable_get(:@
|
153
|
+
@controller.instance_variable_get(:@project).should == :some_project
|
154
154
|
end
|
155
155
|
|
156
156
|
it "should not load through parent resource if instance isn't loaded" do
|
157
157
|
@params.merge!(:action => "show", :id => 123)
|
158
|
-
stub(
|
159
|
-
resource = CanCan::ControllerResource.new(@controller, :through => :
|
158
|
+
stub(Project).find(123) { :some_project }
|
159
|
+
resource = CanCan::ControllerResource.new(@controller, :through => :category)
|
160
160
|
resource.load_resource
|
161
|
-
@controller.instance_variable_get(:@
|
161
|
+
@controller.instance_variable_get(:@project).should == :some_project
|
162
|
+
end
|
163
|
+
|
164
|
+
it "should authorize nested resource through parent association on index action" do
|
165
|
+
@params.merge!(:action => "index")
|
166
|
+
category = Object.new
|
167
|
+
@controller.instance_variable_set(:@category, category)
|
168
|
+
stub(@controller).authorize!(:index, category => Project) { raise CanCan::AccessDenied }
|
169
|
+
resource = CanCan::ControllerResource.new(@controller, :through => :category)
|
170
|
+
lambda { resource.authorize_resource }.should raise_error(CanCan::AccessDenied)
|
162
171
|
end
|
163
172
|
|
164
173
|
it "should load through first matching if multiple are given" do
|
165
174
|
@params.merge!(:action => "show", :id => 123)
|
166
|
-
|
167
|
-
@controller.instance_variable_set(:@
|
168
|
-
stub(
|
169
|
-
resource = CanCan::ControllerResource.new(@controller, :through => [:
|
175
|
+
category = Object.new
|
176
|
+
@controller.instance_variable_set(:@category, category)
|
177
|
+
stub(category).projects.stub!.find(123) { :some_project }
|
178
|
+
resource = CanCan::ControllerResource.new(@controller, :through => [:category, :user])
|
170
179
|
resource.load_resource
|
171
|
-
@controller.instance_variable_get(:@
|
180
|
+
@controller.instance_variable_get(:@project).should == :some_project
|
172
181
|
end
|
173
182
|
|
174
183
|
it "should find record through has_one association with :singleton option" do
|
175
184
|
@params.merge!(:action => "show")
|
176
|
-
|
177
|
-
@controller.instance_variable_set(:@
|
178
|
-
stub(
|
179
|
-
resource = CanCan::ControllerResource.new(@controller, :through => :
|
185
|
+
category = Object.new
|
186
|
+
@controller.instance_variable_set(:@category, category)
|
187
|
+
stub(category).project { :some_project }
|
188
|
+
resource = CanCan::ControllerResource.new(@controller, :through => :category, :singleton => true)
|
180
189
|
resource.load_resource
|
181
|
-
@controller.instance_variable_get(:@
|
190
|
+
@controller.instance_variable_get(:@project).should == :some_project
|
182
191
|
end
|
183
192
|
|
184
193
|
it "should build record through has_one association with :singleton option" do
|
185
|
-
@params.merge!(:action => "create", :
|
186
|
-
|
187
|
-
@controller.instance_variable_set(:@
|
188
|
-
stub(
|
189
|
-
resource = CanCan::ControllerResource.new(@controller, :through => :
|
194
|
+
@params.merge!(:action => "create", :project => {:name => "foobar"})
|
195
|
+
category = Object.new
|
196
|
+
@controller.instance_variable_set(:@category, category)
|
197
|
+
stub(category).build_project { Project.new }
|
198
|
+
resource = CanCan::ControllerResource.new(@controller, :through => :category, :singleton => true)
|
190
199
|
resource.load_resource
|
191
|
-
@controller.instance_variable_get(:@
|
200
|
+
@controller.instance_variable_get(:@project).name.should == "foobar"
|
192
201
|
end
|
193
202
|
|
194
203
|
it "should only authorize :read action on parent resource" do
|
195
|
-
@params.merge!(:action => "new", :
|
196
|
-
stub(
|
197
|
-
stub(@controller).authorize!(:read, :
|
198
|
-
resource = CanCan::ControllerResource.new(@controller, :
|
204
|
+
@params.merge!(:action => "new", :project_id => 123)
|
205
|
+
stub(Project).find(123) { :some_project }
|
206
|
+
stub(@controller).authorize!(:read, :some_project) { raise CanCan::AccessDenied }
|
207
|
+
resource = CanCan::ControllerResource.new(@controller, :project, :parent => true)
|
199
208
|
lambda { resource.load_and_authorize_resource }.should raise_error(CanCan::AccessDenied)
|
200
209
|
end
|
201
210
|
|
202
211
|
it "should load the model using a custom class" do
|
203
212
|
@params.merge!(:action => "show", :id => 123)
|
204
|
-
stub(
|
205
|
-
resource = CanCan::ControllerResource.new(@controller, :class =>
|
213
|
+
stub(Project).find(123) { :some_project }
|
214
|
+
resource = CanCan::ControllerResource.new(@controller, :class => Project)
|
206
215
|
resource.load_resource
|
207
|
-
@controller.instance_variable_get(:@
|
216
|
+
@controller.instance_variable_get(:@project).should == :some_project
|
208
217
|
end
|
209
218
|
|
210
219
|
it "should authorize based on resource name if class is false" do
|
211
220
|
@params.merge!(:action => "show", :id => 123)
|
212
|
-
stub(@controller).authorize!(:show, :
|
221
|
+
stub(@controller).authorize!(:show, :project) { raise CanCan::AccessDenied }
|
213
222
|
resource = CanCan::ControllerResource.new(@controller, :class => false)
|
214
223
|
lambda { resource.authorize_resource }.should raise_error(CanCan::AccessDenied)
|
215
224
|
end
|
216
225
|
|
217
226
|
it "should load and authorize using custom instance name" do
|
218
227
|
@params.merge!(:action => "show", :id => 123)
|
219
|
-
stub(
|
220
|
-
stub(@controller).authorize!(:show, :
|
221
|
-
resource = CanCan::ControllerResource.new(@controller, :instance_name => :
|
228
|
+
stub(Project).find(123) { :some_project }
|
229
|
+
stub(@controller).authorize!(:show, :some_project) { raise CanCan::AccessDenied }
|
230
|
+
resource = CanCan::ControllerResource.new(@controller, :instance_name => :custom_project)
|
222
231
|
lambda { resource.load_and_authorize_resource }.should raise_error(CanCan::AccessDenied)
|
223
|
-
@controller.instance_variable_get(:@
|
232
|
+
@controller.instance_variable_get(:@custom_project).should == :some_project
|
224
233
|
end
|
225
234
|
|
226
235
|
it "should load resource using custom find_by attribute" do
|
227
236
|
@params.merge!(:action => "show", :id => 123)
|
228
|
-
stub(
|
237
|
+
stub(Project).find_by_name!(123) { :some_project }
|
229
238
|
resource = CanCan::ControllerResource.new(@controller, :find_by => :name)
|
230
239
|
resource.load_resource
|
231
|
-
@controller.instance_variable_get(:@
|
240
|
+
@controller.instance_variable_get(:@project).should == :some_project
|
232
241
|
end
|
233
242
|
|
234
243
|
it "should raise ImplementationRemoved when adding :name option" do
|
@@ -239,13 +248,13 @@ describe CanCan::ControllerResource do
|
|
239
248
|
|
240
249
|
it "should raise ImplementationRemoved exception when specifying :resource option since it is no longer used" do
|
241
250
|
lambda {
|
242
|
-
CanCan::ControllerResource.new(@controller, :resource =>
|
251
|
+
CanCan::ControllerResource.new(@controller, :resource => Project)
|
243
252
|
}.should raise_error(CanCan::ImplementationRemoved)
|
244
253
|
end
|
245
254
|
|
246
255
|
it "should raise ImplementationRemoved exception when passing :nested option" do
|
247
256
|
lambda {
|
248
|
-
CanCan::ControllerResource.new(@controller, :nested => :
|
257
|
+
CanCan::ControllerResource.new(@controller, :nested => :project)
|
249
258
|
}.should raise_error(CanCan::ImplementationRemoved)
|
250
259
|
end
|
251
260
|
end
|