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.
@@ -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