heimdallr-resource 1.0.3 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. data/.rspec +1 -2
  2. data/CHANGELOG.md +9 -0
  3. data/README.md +9 -5
  4. data/heimdallr-resource.gemspec +4 -3
  5. data/lib/heimdallr-resource.rb +2 -0
  6. data/lib/heimdallr/resource.rb +21 -191
  7. data/lib/heimdallr/resource_implementation.rb +190 -0
  8. data/spec/{resource_spec.rb → controllers/entities_controller_spec.rb} +25 -7
  9. data/spec/controllers/fluffies_controller_spec.rb +20 -0
  10. data/spec/controllers/things_controller_spec.rb +31 -0
  11. data/spec/dummy/app/controllers/{entity_controller.rb → entities_controller.rb} +6 -2
  12. data/spec/dummy/app/controllers/things_controller.rb +29 -0
  13. data/spec/dummy/app/models/entity.rb +2 -0
  14. data/spec/dummy/app/models/thing.rb +16 -0
  15. data/spec/dummy/config/application.rb +1 -1
  16. data/spec/dummy/config/routes.rb +6 -5
  17. data/spec/dummy/db/schema.rb +5 -0
  18. data/spec/models/resource_implementation_spec.rb +382 -0
  19. data/spec/models/resource_spec.rb +91 -0
  20. data/spec/spec_helper.rb +1 -0
  21. metadata +44 -48
  22. data/spec/dummy/Rakefile +0 -7
  23. data/spec/dummy/app/helpers/application_helper.rb +0 -2
  24. data/spec/dummy/config/environments/development.rb +0 -23
  25. data/spec/dummy/config/initializers/backtrace_silencers.rb +0 -7
  26. data/spec/dummy/config/initializers/inflections.rb +0 -10
  27. data/spec/dummy/config/initializers/mime_types.rb +0 -5
  28. data/spec/dummy/config/initializers/secret_token.rb +0 -7
  29. data/spec/dummy/config/initializers/session_store.rb +0 -8
  30. data/spec/dummy/config/locales/en.yml +0 -5
  31. data/spec/dummy/public/404.html +0 -26
  32. data/spec/dummy/public/422.html +0 -26
  33. data/spec/dummy/public/500.html +0 -26
  34. data/spec/dummy/public/favicon.ico +0 -0
  35. data/spec/dummy/public/stylesheets/.gitkeep +0 -0
  36. data/spec/dummy/script/rails +0 -6
  37. data/spec/fluffies_spec.rb +0 -22
@@ -1,11 +1,16 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe EntityController, :type => :controller do
3
+ describe EntitiesController, :type => :controller do
4
4
  before(:all) do
5
+ User.destroy_all
6
+ Entity.destroy_all
7
+
5
8
  @john = User.create! :admin => false
6
9
  @maria = User.create! :admin => false
7
10
  @admin = User.create! :admin => true
11
+
8
12
  @private = Entity.create! :name => 'ent1', :public => false
13
+ @private_own = Entity.create! :name => 'ent1', :public => false, :owner_id => @john.id
9
14
  @public = Entity.create! :name => 'ent1', :public => true, :owner_id => @john.id
10
15
  end
11
16
 
@@ -14,14 +19,27 @@ describe EntityController, :type => :controller do
14
19
  User.mock @admin
15
20
  get :index
16
21
 
17
- assigns(:entities).count.should == 2
22
+ assigns(:entities).should have(3).items
18
23
  end
19
24
 
20
25
  it "hides non-public entities" do
21
26
  User.mock @john
22
27
  get :index
23
28
 
24
- assigns(:entities).count.should == 1
29
+ assigns(:entities).should have(2).items
30
+ end
31
+
32
+ it "shows private to owner" do
33
+ User.mock @john
34
+ get :show, {:id => @private_own.id}
35
+
36
+ assigns(:entity).insecure.should == @private_own
37
+ end
38
+
39
+ it "hides private from non-owner" do
40
+ User.mock @maria
41
+
42
+ expect { get :show, {:id => @private_own.id} }.to raise_error
25
43
  end
26
44
 
27
45
  it "allows creation for admin" do
@@ -33,7 +51,7 @@ describe EntityController, :type => :controller do
33
51
 
34
52
  it "disallows creation for non-admin" do
35
53
  User.mock @john
36
- expect { post :create, {} }.should raise_error
54
+ expect { post :create, {} }.to raise_error
37
55
  end
38
56
 
39
57
  it "allows update for admin" do
@@ -46,7 +64,7 @@ describe EntityController, :type => :controller do
46
64
 
47
65
  it "disallows update for non-admin" do
48
66
  User.mock @john
49
- expect { post :update, {:id => @public.id} }.should raise_error
67
+ expect { post :update, {:id => @public.id} }.to raise_error
50
68
  end
51
69
 
52
70
  it "allows destroy for admin" do
@@ -67,7 +85,7 @@ describe EntityController, :type => :controller do
67
85
 
68
86
  it "disallows destroy for nobody" do
69
87
  User.mock @maria
70
- expect { post :destroy, {:id => @public.id} }.should raise_error
88
+ expect { post :destroy, {:id => @public.id} }.to raise_error
71
89
  end
72
90
 
73
91
  it "assigns the custom methods" do
@@ -78,4 +96,4 @@ describe EntityController, :type => :controller do
78
96
  assigns(:entity).id.should == @public.id
79
97
  end
80
98
  end
81
- end
99
+ end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+
3
+ describe FluffiesController, :type => :controller do
4
+ before(:all) do
5
+ User.destroy_all
6
+ Entity.destroy_all
7
+
8
+ @admin = User.create! :admin => true
9
+
10
+ @entity1 = Entity.create! :name => 'entity 1'
11
+ @entity2 = Entity.create! :name => 'entity 2'
12
+ end
13
+
14
+ it "loads entity resources and assigns to @entities" do
15
+ User.mock @admin
16
+ get :index
17
+
18
+ assigns(:entities).should have(2).items
19
+ end
20
+ end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+
3
+ describe ThingsController, :type => :controller do
4
+ before(:all) do
5
+ User.delete_all
6
+ Entity.delete_all
7
+
8
+ @admin = User.create! :admin => true
9
+
10
+ @entity1 = Entity.create! :name => 'entity 1'
11
+ @entity2 = Entity.create! :name => 'entity 2'
12
+
13
+ @thing1 = Thing.create! :name => 'thing 1', :entity_id => @entity1.id
14
+ @thing2 = Thing.create! :name => 'thing 2', :entity_id => @entity1.id
15
+ @thing3 = Thing.create! :name => 'thing 3', :entity_id => @entity2.id
16
+ end
17
+
18
+ it "loads entity resource and assigns to @entity" do
19
+ User.mock @admin
20
+ get :index, :entity_id => @entity1.id
21
+
22
+ assigns(:entity).id.should == @entity1.id
23
+ end
24
+
25
+ it "loads thing resources through @entity and assigns to @things" do
26
+ User.mock @admin
27
+ get :index, :entity_id => @entity1.id
28
+
29
+ assigns(:things).should have(2).items
30
+ end
31
+ end
@@ -1,4 +1,4 @@
1
- class EntityController < ApplicationController
1
+ class EntitiesController < ApplicationController
2
2
  include Heimdallr::Resource
3
3
 
4
4
  load_and_authorize_resource
@@ -7,6 +7,10 @@ class EntityController < ApplicationController
7
7
  render :nothing => true
8
8
  end
9
9
 
10
+ def show
11
+ render :nothing => true
12
+ end
13
+
10
14
  def new
11
15
  render :nothing => true
12
16
  end
@@ -30,4 +34,4 @@ class EntityController < ApplicationController
30
34
  def penetrate
31
35
  render :nothing => true
32
36
  end
33
- end
37
+ end
@@ -0,0 +1,29 @@
1
+ class ThingsController < ApplicationController
2
+ include Heimdallr::Resource
3
+
4
+ load_and_authorize_resource :through => :entity
5
+
6
+ def index
7
+ render :nothing => true
8
+ end
9
+
10
+ def new
11
+ render :nothing => true
12
+ end
13
+
14
+ def create
15
+ render :nothing => true
16
+ end
17
+
18
+ def edit
19
+ render :nothing => true
20
+ end
21
+
22
+ def update
23
+ render :nothing => true
24
+ end
25
+
26
+ def destroy
27
+ render :nothing => true
28
+ end
29
+ end
@@ -1,6 +1,8 @@
1
1
  class Entity < ActiveRecord::Base
2
2
  include Heimdallr::Model
3
3
 
4
+ has_many :things, :dependent => :destroy
5
+
4
6
  restrict do |user, record|
5
7
  if user.admin
6
8
  scope :fetch
@@ -0,0 +1,16 @@
1
+ class Thing < ActiveRecord::Base
2
+ include Heimdallr::Model
3
+
4
+ belongs_to :entity
5
+
6
+ restrict do |user, record|
7
+ if user.admin
8
+ scope :fetch
9
+ scope :delete
10
+ can [:view, :create, :update]
11
+ else
12
+ scope :fetch, -> { where('public = ? or owner_id = ?', true, user.id) }
13
+ scope :delete, -> { where('owner_id = ?', user.id) }
14
+ end
15
+ end
16
+ end
@@ -5,7 +5,7 @@ require "rails/all"
5
5
  Bundler.require(:default, Rails.env)
6
6
 
7
7
  require "heimdallr"
8
- require "heimdallr/resource"
8
+ require "heimdallr-resource"
9
9
 
10
10
  module Dummy
11
11
  class Application < Rails::Application
@@ -1,8 +1,9 @@
1
1
  Dummy::Application.routes.draw do
2
- resources :entity do
3
- member do
4
- post :penetrate
5
- end
2
+ resources :entities do
3
+ resources :things
4
+
5
+ post :penetrate, :on => :member
6
6
  end
7
+
7
8
  resources :fluffies
8
- end
9
+ end
@@ -5,6 +5,11 @@ ActiveRecord::Schema.define(:version => 1) do
5
5
  t.boolean "public"
6
6
  end
7
7
 
8
+ create_table "things", :force => true do |t|
9
+ t.integer "entity_id"
10
+ t.string "name"
11
+ end
12
+
8
13
  create_table "users", :force => true do |t|
9
14
  t.boolean "admin"
10
15
  end
@@ -0,0 +1,382 @@
1
+ require 'spec_helper'
2
+
3
+ describe Heimdallr::ResourceImplementation do
4
+ let(:controller) { Object.new }
5
+ let(:params) { HashWithIndifferentAccess.new :controller => :entities }
6
+ let(:entity) { stub!.id{1}.subject }
7
+ before do
8
+ stub(controller).params { params }
9
+ stub(controller).skip_authorization_check? { false }
10
+ end
11
+
12
+ describe '#load_resource' do
13
+ it "loads and assigns the resource to an instance variable for show action" do
14
+ params.merge! :action => 'show', :id => entity.id
15
+ stub(Entity).scoped.mock!.find(entity.id) { entity }
16
+ resource = Heimdallr::ResourceImplementation.new controller, :resource => 'entity'
17
+ resource.load_resource
18
+ controller.instance_variable_get(:@entity).should == entity
19
+ end
20
+
21
+ it "loads and assigns the resource to an instance variable for edit action" do
22
+ params.merge! :action => 'edit', :id => entity.id
23
+ stub(Entity).scoped.mock!.find(entity.id) { entity }
24
+ resource = Heimdallr::ResourceImplementation.new controller, :resource => 'entity'
25
+ resource.load_resource
26
+ controller.instance_variable_get(:@entity).should == entity
27
+ end
28
+
29
+ it "loads and assigns the resource to an instance variable for update action" do
30
+ params.merge! :action => 'edit', :id => entity.id
31
+ stub(Entity).scoped.mock!.find(entity.id) { entity }
32
+ resource = Heimdallr::ResourceImplementation.new controller, :resource => 'entity'
33
+ resource.load_resource
34
+ controller.instance_variable_get(:@entity).should == entity
35
+ end
36
+
37
+ it "loads and assigns the resource to an instance variable for destroy action" do
38
+ params.merge! :action => 'destroy', :id => entity.id
39
+ stub(Entity).scoped.mock!.find(entity.id) { entity }
40
+ resource = Heimdallr::ResourceImplementation.new controller, :resource => 'entity'
41
+ resource.load_resource
42
+ controller.instance_variable_get(:@entity).should == entity
43
+ end
44
+
45
+ it "builds and assigns a new resource for new action" do
46
+ params.merge! :action => 'new'
47
+ mock(Entity).new({}) { :new_entity }
48
+ resource = Heimdallr::ResourceImplementation.new controller, :resource => 'entity'
49
+ resource.load_resource
50
+ controller.instance_variable_get(:@entity).should == :new_entity
51
+ end
52
+
53
+ it "builds and assigns a new resource for create action" do
54
+ params.merge! :action => 'create', :entity => {:name => 'foo'}
55
+ mock(Entity).new('name' => 'foo') { :new_entity }
56
+ resource = Heimdallr::ResourceImplementation.new controller, :resource => 'entity'
57
+ resource.load_resource
58
+ controller.instance_variable_get(:@entity).should == :new_entity
59
+ end
60
+
61
+ it "loads and assigns a resource collection for index action" do
62
+ params.merge! :action => 'index'
63
+ mock(Entity).scoped { :entity_collection }
64
+ resource = Heimdallr::ResourceImplementation.new controller, :resource => 'entity'
65
+ resource.load_resource
66
+ controller.instance_variable_get(:@entities).should == :entity_collection
67
+ end
68
+
69
+ it "loads and assigns a namespaced resource" do
70
+ params.merge! :action => 'show', :id => entity.id
71
+ module SomeProject
72
+ class Entity < ::Entity; end
73
+ end
74
+ stub(SomeProject::Entity).scoped.mock!.find(entity.id) { entity }
75
+ resource = Heimdallr::ResourceImplementation.new controller, :resource => 'some_project/entity'
76
+ resource.load_resource
77
+ controller.instance_variable_get(:@some_project_entity).should == entity
78
+ end
79
+
80
+ it "loads the resource with a custom finder" do
81
+ params.merge! :action => 'show', :id => entity.id
82
+ stub(Entity).scoped.mock!.find_by_name(entity.id) { entity }
83
+ resource = Heimdallr::ResourceImplementation.new controller, :resource => 'entity', :finder => :find_by_name
84
+ resource.load_resource
85
+ controller.instance_variable_get(:@entity).should == entity
86
+ end
87
+
88
+ it "loads and assigns a single resource for custom action by default" do
89
+ params.merge! :action => 'fetch', :id => entity.id
90
+ stub(Entity).scoped.mock!.find(entity.id) { entity }
91
+ resource = Heimdallr::ResourceImplementation.new controller, :resource => 'entity'
92
+ resource.load_resource
93
+ controller.instance_variable_get(:@entity).should == entity
94
+ end
95
+
96
+ it "loads and assigns a collection for custom action if specified in options" do
97
+ params.merge! :action => 'sort'
98
+ mock(Entity).scoped { :entity_collection }
99
+ resource = Heimdallr::ResourceImplementation.new controller, :resource => 'entity', :collection => [:sort]
100
+ resource.load_resource
101
+ controller.instance_variable_get(:@entities).should == :entity_collection
102
+ end
103
+
104
+ it "builds and assigns a new resource for custom action if specified in options" do
105
+ params.merge! :action => 'generate', :entity => {:name => 'foo'}
106
+ mock(Entity).new('name' => 'foo') { :new_entity }
107
+ resource = Heimdallr::ResourceImplementation.new controller, :resource => 'entity', :new_record => [:generate]
108
+ resource.load_resource
109
+ controller.instance_variable_get(:@entity).should == :new_entity
110
+ end
111
+
112
+ it "doesn't assign the resource to an instance variable if it is already assigned" do
113
+ params.merge! :action => 'show', :id => entity.id
114
+ controller.instance_variable_set :@entity, :different_entity
115
+ stub(Entity).scoped.stub!.find(entity.id) { entity }
116
+ resource = Heimdallr::ResourceImplementation.new controller, :resource => 'entity'
117
+ resource.load_resource
118
+ controller.instance_variable_get(:@entity).should == :different_entity
119
+ end
120
+
121
+ it "loads and assigns a resource through the association of another parent resource" do
122
+ thing = stub!.id{1}.subject
123
+ params.merge! :controller => :things, :action => 'show', :entity_id => entity.id, :id => thing.id
124
+ controller.instance_variable_set(:@entity, entity)
125
+ stub(entity).things.mock!.find(thing.id) { thing }
126
+ resource = Heimdallr::ResourceImplementation.new controller, :resource => 'thing', :through => 'entity'
127
+ resource.load_resource
128
+ controller.instance_variable_get(:@thing).should == thing
129
+ end
130
+
131
+ it "loads and assigns the parent resource if :through option is provided" do
132
+ params.merge! :controller => :things, :action => 'index', :entity_id => entity.id
133
+ stub(Entity).scoped.mock!.find(entity.id) { entity }
134
+ stub(entity).things
135
+ resource = Heimdallr::ResourceImplementation.new controller, :resource => 'thing', :through => 'entity'
136
+ resource.load_resource
137
+ controller.instance_variable_get(:@entity).should == entity
138
+ end
139
+
140
+ it "loads the resource directly if the parent isn't found and :shallow option is true" do
141
+ thing = stub!.id{1}.subject
142
+ params.merge! :controller => :things, :action => 'show', :id => thing.id
143
+ stub(Thing).scoped.mock!.find(thing.id) { thing }
144
+ resource = Heimdallr::ResourceImplementation.new controller, :resource => 'thing', :through => 'entity', :shallow => true
145
+ resource.load_resource
146
+ controller.instance_variable_get(:@thing).should == thing
147
+ end
148
+
149
+ it "raises an error when the parent's id is not provided" do
150
+ params.merge! :controller => :things, :action => 'show', :id => 1
151
+ resource = Heimdallr::ResourceImplementation.new controller, :resource => 'thing', :through => 'entity'
152
+ expect { resource.load_resource }.to raise_error(RuntimeError)
153
+ end
154
+
155
+ it "loads through the first parent found when multiple are given" do
156
+ thing = stub!.id{1}.subject
157
+ params.merge! :controller => :things, :action => 'show', :id => thing.id
158
+ class Nothing; end
159
+ stub(Nothing).scoped
160
+ controller.instance_variable_set(:@entity, entity)
161
+ controller.instance_variable_set(:@user, Object.new)
162
+ stub(entity).things.mock!.find(thing.id) { thing }
163
+ resource = Heimdallr::ResourceImplementation.new controller, :resource => 'thing', :through => [:nothing, :entity, :user]
164
+ resource.load_resource
165
+ controller.instance_variable_get(:@thing).should == thing
166
+ end
167
+
168
+ it "loads through has_one association with :singleton option" do
169
+ thing = stub!.id{1}.subject
170
+ params.merge! :controller => :things, :action => 'show'
171
+ controller.instance_variable_set(:@entity, entity)
172
+ mock(entity).thing { thing }
173
+ resource = Heimdallr::ResourceImplementation.new controller, :resource => 'thing', :through => 'entity', :singleton => true
174
+ resource.load_resource
175
+ controller.instance_variable_get(:@thing).should == thing
176
+ end
177
+
178
+ it "builds a record through has_one association with :singleton option" do
179
+ params.merge! :controller => :things, :action => 'create', :thing => {:name => 'foo'}
180
+ controller.instance_variable_set(:@entity, entity)
181
+ thing = stub!.id{1}.subject
182
+ stub(entity).thing { nil }
183
+ mock(entity).build_thing('name' => 'foo') { thing }
184
+ resource = Heimdallr::ResourceImplementation.new controller, :resource => 'thing', :through => 'entity', :singleton => true
185
+ resource.load_resource
186
+ controller.instance_variable_get(:@thing).should == thing
187
+ end
188
+
189
+ it "builds a record with correct method name with :singleton and :through_association options" do
190
+ params.merge! :controller => :things, :action => 'create', :thing => {:name => 'foo'}
191
+ controller.instance_variable_set(:@entity, entity)
192
+ thing = stub!.id{1}.subject
193
+ stub(entity).stuff { nil }
194
+ mock(entity).build_stuff('name' => 'foo') { thing }
195
+ resource = Heimdallr::ResourceImplementation.new controller, :resource => 'thing', :through => 'entity', :singleton => true, :through_association => :stuff
196
+ resource.load_resource
197
+ controller.instance_variable_get(:@thing).should == thing
198
+ end
199
+
200
+ it "doesn't build a record through has_one association with :singleton option if one already exists because it can cause it to delete it in the database" do
201
+ params.merge! :controller => :things, :action => 'create', :thing => {:name => 'foo'}
202
+ controller.instance_variable_set(:@entity, entity)
203
+ thing = stub!.id{1}.subject
204
+ mock(entity).thing { thing }
205
+ mock(thing).assign_attributes 'name' => 'foo'
206
+ resource = Heimdallr::ResourceImplementation.new controller, :resource => 'thing', :through => 'entity', :singleton => true
207
+ resource.load_resource
208
+ controller.instance_variable_get(:@thing).should == thing
209
+ end
210
+
211
+ it "loads through has_one association with :singleton and :shallow options" do
212
+ thing = stub!.id{1}.subject
213
+ params.merge! :controller => :things, :action => 'show', :id => thing.id
214
+ stub(Thing).scoped.mock!.find(thing.id) { thing }
215
+ resource = Heimdallr::ResourceImplementation.new controller, :resource => 'thing', :through => 'entity', :singleton => true, :shallow => :true
216
+ resource.load_resource
217
+ controller.instance_variable_get(:@thing).should == thing
218
+ end
219
+
220
+ it "builds a record through has_one association with :singleton and :shallow options" do
221
+ params.merge! :controller => :things, :action => 'create', :thing => {:name => 'foo'}
222
+ stub(Thing).scoped.mock!.new('name' => 'foo') { :new_thing }
223
+ resource = Heimdallr::ResourceImplementation.new controller, :resource => 'thing', :through => 'entity', :singleton => true, :shallow => :true
224
+ resource.load_resource
225
+ controller.instance_variable_get(:@thing).should == :new_thing
226
+ end
227
+
228
+ it "builds a record through has_one association with :singleton and :shallow options even if the parent is present" do
229
+ params.merge! :controller => :things, :action => 'create', :thing => {:name => 'foo'}
230
+ controller.instance_variable_set(:@entity, entity)
231
+ stub(entity).thing { nil }
232
+ mock(entity).build_thing('name' => 'foo') { :new_thing }
233
+ resource = Heimdallr::ResourceImplementation.new controller, :resource => 'thing', :through => 'entity', :singleton => true, :shallow => :true
234
+ resource.load_resource
235
+ controller.instance_variable_get(:@thing).should == :new_thing
236
+ end
237
+
238
+ it "loads through custom association if :through_association option is provided" do
239
+ thing = stub!.id{1}.subject
240
+ params.merge! :controller => :things, :action => 'show', :entity_id => entity.id, :id => thing.id
241
+ controller.instance_variable_set(:@entity, entity)
242
+ stub(entity).stuff.mock!.find(thing.id) { thing }
243
+ resource = Heimdallr::ResourceImplementation.new controller, :resource => 'thing', :through => 'entity', :through_association => :stuff
244
+ resource.load_resource
245
+ controller.instance_variable_get(:@thing).should == thing
246
+ end
247
+
248
+ it "loads through custom association if both :through_association and :singleton options are provided" do
249
+ thing = stub!.id{1}.subject
250
+ params.merge! :controller => :things, :action => 'show', :entity_id => entity.id, :id => thing.id
251
+ controller.instance_variable_set(:@entity, entity)
252
+ mock(entity).stuff { thing }
253
+ resource = Heimdallr::ResourceImplementation.new controller, :resource => 'thing', :through => 'entity', :through_association => :stuff, :singleton => true
254
+ resource.load_resource
255
+ controller.instance_variable_get(:@thing).should == thing
256
+ end
257
+
258
+ it "loads and assigns a resource using custom instance name" do
259
+ params.merge! :action => 'show', :id => entity.id
260
+ stub(Entity).scoped.mock!.find(entity.id) { entity }
261
+ resource = Heimdallr::ResourceImplementation.new controller, :resource => 'entity', :instance_name => :something
262
+ resource.load_resource
263
+ controller.instance_variable_get(:@something).should == entity
264
+ end
265
+
266
+ it "loads and assigns a resource collection using custom instance name" do
267
+ params.merge! :action => 'index'
268
+ mock(Entity).scoped { :entity_collection }
269
+ resource = Heimdallr::ResourceImplementation.new controller, :resource => 'entity', :instance_name => :something
270
+ resource.load_resource
271
+ controller.instance_variable_get(:@somethings).should == :entity_collection
272
+ end
273
+ end
274
+
275
+ describe '#load_and_authorize_resource' do
276
+ let(:user) { stub!.id{1}.subject }
277
+ before do
278
+ stub(user).admin { false }
279
+ stub(controller).security_context { user }
280
+ end
281
+
282
+ it "calls #restrict on the loaded resource" do
283
+ params.merge! :action => 'show', :id => entity.id
284
+ mock(Entity).restrict(controller.security_context).stub!.find(entity.id) { entity }
285
+ resource = Heimdallr::ResourceImplementation.new controller, :resource => 'entity'
286
+ resource.load_and_authorize_resource
287
+ end
288
+
289
+ it "raises AccessDenied when calling :new action for resource that can't be created" do
290
+ params.merge! :action => 'new'
291
+ mock(Entity).new.mock!.restrict(controller.security_context, {}) { entity }
292
+ stub(entity).assign_attributes
293
+ mock(entity).creatable? { false }
294
+ resource = Heimdallr::ResourceImplementation.new controller, :resource => 'entity'
295
+ expect { resource.load_and_authorize_resource }.to raise_error(Heimdallr::AccessDenied)
296
+ end
297
+
298
+ it "raises AccessDenied when creating a resource that can't be created" do
299
+ params.merge! :action => 'create'
300
+ mock(Entity).new.mock!.restrict(controller.security_context, {}) { entity }
301
+ stub(entity).assign_attributes
302
+ mock(entity).creatable? { false }
303
+ resource = Heimdallr::ResourceImplementation.new controller, :resource => 'entity'
304
+ expect { resource.load_and_authorize_resource }.to raise_error(Heimdallr::AccessDenied)
305
+ end
306
+
307
+ it "raises AccessDenied when calling :edit action for resource that can't be updated" do
308
+ params.merge! :action => 'edit', :id => entity.id
309
+ mock(Entity).restrict(controller.security_context).stub!.find(entity.id) { entity }
310
+ mock(entity).modifiable? { false }
311
+ resource = Heimdallr::ResourceImplementation.new controller, :resource => 'entity'
312
+ expect { resource.load_and_authorize_resource }.to raise_error(Heimdallr::AccessDenied)
313
+ end
314
+
315
+ it "raises AccessDenied when updating a resource that can't be updated" do
316
+ params.merge! :action => 'update', :id => entity.id
317
+ mock(Entity).restrict(controller.security_context).stub!.find(entity.id) { entity }
318
+ mock(entity).modifiable? { false }
319
+ resource = Heimdallr::ResourceImplementation.new controller, :resource => 'entity'
320
+ expect { resource.load_and_authorize_resource }.to raise_error(Heimdallr::AccessDenied)
321
+ end
322
+
323
+ it "raises AccessDenied when destroying a resource that can't be destroyed" do
324
+ params.merge! :action => 'destroy', :id => entity.id
325
+ mock(Entity).restrict(controller.security_context).stub!.find(entity.id) { entity }
326
+ mock(entity).destroyable? { false }
327
+ resource = Heimdallr::ResourceImplementation.new controller, :resource => 'entity'
328
+ expect { resource.load_and_authorize_resource }.to raise_error(Heimdallr::AccessDenied)
329
+ end
330
+
331
+ it "fixates certain attributes of a new resource" do
332
+ params.merge! :action => 'new', :entity => {:name => 'foo'}
333
+ mock(Entity).new.mock!.restrict(controller.security_context, {}) { entity }
334
+ mock(entity).creatable? { true }
335
+ fixtures = {:create => {:name => 'bar'}}
336
+ stub(entity).reflect_on_security { {:restrictions => stub!.fixtures{fixtures}.subject} }
337
+ stub(entity).assign_attributes('name' => 'foo')
338
+ mock(entity).assign_attributes(fixtures[:create])
339
+ resource = Heimdallr::ResourceImplementation.new controller, :resource => 'entity'
340
+ resource.load_and_authorize_resource
341
+ controller.instance_variable_get(:@entity) == entity
342
+ end
343
+
344
+ it "fixates certain attributes of an updating resource" do
345
+ params.merge! :action => 'update', :id => entity.id, :entity => {:name => 'foo'}
346
+ mock(Entity).restrict(controller.security_context).stub!.find(entity.id) { entity }
347
+ mock(entity).modifiable? { true }
348
+ fixtures = {:update => {:name => 'bar'}}
349
+ stub(entity).reflect_on_security { {:restrictions => stub!.fixtures{fixtures}.subject} }
350
+ stub(entity).assign_attributes('name' => 'foo')
351
+ mock(entity).assign_attributes(fixtures[:update])
352
+ resource = Heimdallr::ResourceImplementation.new controller, :resource => 'entity'
353
+ resource.load_and_authorize_resource
354
+ controller.instance_variable_get(:@entity) == entity
355
+ end
356
+
357
+ context "when controller.skip_authorization_check? is true" do
358
+ before { stub(controller).skip_authorization_check? { true } }
359
+
360
+ it "doesn't raise AccessDenied" do
361
+ params.merge! :action => 'destroy', :id => entity.id
362
+ mock(Entity).restrict(controller.security_context).stub!.find(entity.id) { entity }
363
+ stub(entity).destroyable? { false }
364
+ resource = Heimdallr::ResourceImplementation.new controller, :resource => 'entity'
365
+ expect { resource.load_and_authorize_resource }.not_to raise_error(Heimdallr::AccessDenied)
366
+ end
367
+
368
+ it "doesn't fixate attributes" do
369
+ params.merge! :action => 'new', :entity => {:name => 'foo'}
370
+ mock(Entity).new.mock!.restrict(controller.security_context, {}) { entity }
371
+ stub(entity).creatable? { true }
372
+ fixtures = {:create => {:name => 'bar'}}
373
+ stub(entity).reflect_on_security { {:restrictions => stub!.fixtures{fixtures}.subject} }
374
+ stub(entity).assign_attributes('name' => 'foo')
375
+ dont_allow(entity).assign_attributes(fixtures[:create])
376
+ resource = Heimdallr::ResourceImplementation.new controller, :resource => 'entity'
377
+ resource.load_and_authorize_resource
378
+ controller.instance_variable_get(:@entity) == entity
379
+ end
380
+ end
381
+ end
382
+ end