cancan 1.3.4 → 1.4.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -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 |object_class, object|
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 pass class with no object if :all objects are accepted and class is passed directly" do
52
- @ability.can :preview, :all do |object_class, object|
53
- object_class.should == Hash
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 be_true
55
+ @ability.can?(:preview, Hash).should be_true
56
+ @block_called.should be_false
59
57
  end
60
58
 
61
- it "should pass action and object for global manage actions" do
62
- @ability.can :manage, Array do |action, object|
63
- action.should == :stuff
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, [1, 2]).should
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 return block result for action, object_class, and object for any action" do
86
- @ability.can :manage, :all do |action, object_class, object|
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 == Fixnum
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, Array]
133
+ @ability.can :update, [String, Range]
126
134
  @ability.can?(:update, "foo").should be_true
127
- @ability.can?(:update, []).should be_true
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, Array, :first => 1, :last => 3
218
- @ability.can?(:read, [1, 2, 3]).should be_true
219
- @ability.can?(:read, [1, 2, 3, 4]).should be_false
220
- @ability.can?(:read, Array).should be_true
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, Array, :first => [1, 3, 5]
225
- @ability.can?(:read, [1, 2, 3]).should be_true
226
- @ability.can?(:read, [2, 3]).should be_false
227
- @ability.can?(:read, [3, 4]).should be_true
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, Array, :first => 1..3
232
- @ability.can?(:read, [1, 2, 3]).should be_true
233
- @ability.can?(:read, [3, 4]).should be_true
234
- @ability.can?(:read, [4, 5]).should be_false
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, Array, :first => { :length => 5 }
239
- @ability.can?(:read, ["foo", "bar"]).should be_false
240
- @ability.can?(:read, ["test1", "foo"]).should be_true
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 allow nested hash of arrays and match any element" do
244
- @ability.can :read, Array, :first => { :to_i => 3 }
245
- @ability.can?(:read, [[1, 2, 3]]).should be_true
246
- @ability.can?(:read, [[4, 5, 6]]).should be_false
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, Array
251
- @ability.cannot :read, Array, :first => 1
252
- @ability.can?(:read, [2, 3, 5]).should be_true
253
- @ability.can?(:read, [1, 3, 5]).should be_false
254
- @ability.can?(:read, Array).should be_true
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 has eated cheezburger" do
258
- lambda {
259
- @ability.can? :has, :cheezburger
260
- }.should raise_error(CanCan::Error, "Nom nom nom. I eated it.")
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(Person)
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
@@ -1,5 +1,6 @@
1
1
  require "spec_helper"
2
2
 
3
+ # Most of CanDefinition functionality is tested in Ability specs
3
4
  describe CanCan::CanDefinition do
4
5
  before(:each) do
5
6
  @conditions = {}
@@ -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 raise access denied exception if ability us unauthorized to perform a certain action" do
18
- begin
19
- @controller.authorize! :read, :foo, 1, 2, 3, :message => "Access denied!"
20
- rescue CanCan::AccessDenied => e
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 => "abilities")
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(Ability).find(123) { :some_resource }
13
+ stub(Project).find(123) { :some_project }
13
14
  resource = CanCan::ControllerResource.new(@controller)
14
15
  resource.load_resource
15
- @controller.instance_variable_get(:@ability).should == :some_resource
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(:@ability, :some_ability)
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(:@ability).should == :some_ability
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/abilities", :action => "show", :id => 123)
28
- stub(Ability).find(123) { :some_resource }
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(:@ability).should == :some_resource
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::AbilitiesController", :action => "show", :id => 123)
36
- stub(Ability).find(123) { :some_resource }
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(:@ability).should == :some_resource
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", :ability => {:foo => "bar"})
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(:@ability).should == :some_resource
47
+ @controller.instance_variable_get(:@project).name.should == "foobar"
48
48
  end
49
49
 
50
- it "should build a new resource with no arguments if attribute hash isn't specified" do
51
- @params[:action] = "new"
52
- mock(Ability).new { :some_resource }
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(:@ability).should == :some_resource
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(:@ability).should be_nil
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(:@ability, :some_resource)
68
- stub(@controller).authorize!(:show, :some_resource) { raise CanCan::AccessDenied }
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, Ability) { raise CanCan::AccessDenied }
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(:@ability).should be_nil
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(Ability).new { :some_resource }
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(:@ability).should == :some_resource
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(:@ability).should be_nil
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, :person)
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, :ability)
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, :ability, {:parent => true})
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, :person, {:parent => false})
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 when supplying a resource with a different name" do
131
- @params.merge!(:action => "index", :person_id => 123)
132
- stub(Person).find(123) { :some_person }
133
- resource = CanCan::ControllerResource.new(@controller, :person)
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(:@person).should == :some_person
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
- person = Object.new
149
- @controller.instance_variable_set(:@person, person)
150
- stub(person).abilities.stub!.find(123) { :some_ability }
151
- resource = CanCan::ControllerResource.new(@controller, :through => :person)
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(:@ability).should == :some_ability
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(Ability).find(123) { :some_ability }
159
- resource = CanCan::ControllerResource.new(@controller, :through => :person)
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(:@ability).should == :some_ability
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
- person = Object.new
167
- @controller.instance_variable_set(:@person, person)
168
- stub(person).abilities.stub!.find(123) { :some_ability }
169
- resource = CanCan::ControllerResource.new(@controller, :through => [:thing, :person])
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(:@ability).should == :some_ability
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
- person = Object.new
177
- @controller.instance_variable_set(:@person, person)
178
- stub(person).ability { :some_ability }
179
- resource = CanCan::ControllerResource.new(@controller, :through => :person, :singleton => true)
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(:@ability).should == :some_ability
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", :ability => :ability_attributes)
186
- person = Object.new
187
- @controller.instance_variable_set(:@person, person)
188
- stub(person).build_ability(:ability_attributes) { :new_ability }
189
- resource = CanCan::ControllerResource.new(@controller, :through => :person, :singleton => true)
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(:@ability).should == :new_ability
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", :person_id => 123)
196
- stub(Person).find(123) { :some_person }
197
- stub(@controller).authorize!(:read, :some_person) { raise CanCan::AccessDenied }
198
- resource = CanCan::ControllerResource.new(@controller, :person)
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(Person).find(123) { :some_resource }
205
- resource = CanCan::ControllerResource.new(@controller, :class => Person)
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(:@ability).should == :some_resource
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, :ability) { raise CanCan::AccessDenied }
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(Ability).find(123) { :some_ability }
220
- stub(@controller).authorize!(:show, :some_ability) { raise CanCan::AccessDenied }
221
- resource = CanCan::ControllerResource.new(@controller, :instance_name => :custom_ability)
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(:@custom_ability).should == :some_ability
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(Ability).find_by_name!(123) { :some_resource }
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(:@ability).should == :some_resource
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 => Person)
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 => :person)
257
+ CanCan::ControllerResource.new(@controller, :nested => :project)
249
258
  }.should raise_error(CanCan::ImplementationRemoved)
250
259
  end
251
260
  end