api_resource 0.3.14 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/api_resource.gemspec +5 -2
- data/lib/api_resource/associations/generic_scope.rb +68 -0
- data/lib/api_resource/associations/resource_scope.rb +11 -15
- data/lib/api_resource/associations/scope.rb +29 -12
- data/lib/api_resource/associations/single_object_proxy.rb +0 -8
- data/lib/api_resource/associations.rb +2 -1
- data/lib/api_resource/decorators/caching_decorator.rb +20 -0
- data/lib/api_resource/decorators.rb +6 -0
- data/lib/api_resource/scopes.rb +3 -0
- data/lib/api_resource.rb +1 -4
- data/spec/lib/associations_spec.rb +119 -109
- data/spec/support/mocks/association_mocks.rb +2 -1
- data/spec/support/requests/association_requests.rb +12 -4
- data/spec/support/requests/test_resource_requests.rb +3 -3
- metadata +56 -53
@@ -3,13 +3,13 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
|
3
3
|
include ApiResource
|
4
4
|
|
5
5
|
describe "Associations" do
|
6
|
-
|
6
|
+
|
7
7
|
after(:all) do
|
8
8
|
TestResource.reload_class_attributes
|
9
9
|
end
|
10
|
-
|
10
|
+
|
11
11
|
context "creating and testing for associations of various types" do
|
12
|
-
|
12
|
+
|
13
13
|
it "should be able to give a list of all associations" do
|
14
14
|
AllAssociations = Class.new(ApiResource::Base)
|
15
15
|
AllAssociations.class_eval do
|
@@ -20,90 +20,90 @@ describe "Associations" do
|
|
20
20
|
AllAssociations.association_names.sort.should eql [:has_many_objects, :belongs_to_object, :has_one_object].sort
|
21
21
|
AllAssociations.new.association_names.sort.should eql [:has_many_objects, :belongs_to_object, :has_one_object].sort
|
22
22
|
end
|
23
|
-
|
23
|
+
|
24
24
|
it "should be be able to define an asociation using a method named after that association type" do
|
25
25
|
TestResource.has_many :has_many_objects
|
26
26
|
TestResource.has_many?(:has_many_objects).should be_true
|
27
27
|
end
|
28
|
-
|
28
|
+
|
29
29
|
it "should be able to define associations with different class names" do
|
30
30
|
TestResource.has_many :test_name, :class_name => :has_many_objects
|
31
31
|
TestResource.has_many?(:test_name).should be_true
|
32
32
|
TestResource.has_many_class_name(:test_name).should eql("HasManyObject")
|
33
33
|
end
|
34
|
-
|
34
|
+
|
35
35
|
it "should be able to define multiple associations at the same time" do
|
36
36
|
TestResource.has_many :has_many_objects, :other_has_many_objects
|
37
37
|
TestResource.has_many?(:has_many_objects).should be_true
|
38
38
|
TestResource.has_many?(:other_has_many_objects).should be_true
|
39
39
|
end
|
40
|
-
|
40
|
+
|
41
41
|
it "should be able to tell if something is an association via the association? method" do
|
42
42
|
TestResource.belongs_to :belongs_to_object
|
43
43
|
TestResource.association?(:belongs_to_object).should be_true
|
44
44
|
end
|
45
|
-
|
45
|
+
|
46
46
|
it "should be able to get the class name of an association via the association_class_name method" do
|
47
47
|
TestResource.belongs_to :belongs_to_object
|
48
48
|
TestResource.association_class_name(:belongs_to_object).should eql("BelongsToObject")
|
49
49
|
TestResource.belongs_to :strange_name, :class_name => :belongs_to_object
|
50
50
|
TestResource.association_class_name(:strange_name).should eql("BelongsToObject")
|
51
51
|
end
|
52
|
-
|
52
|
+
|
53
53
|
it "should only define relationships for the given class - they should not cascade" do
|
54
54
|
TestResource.belongs_to :belongs_to_object
|
55
55
|
AnotherTestResource.association?(:belongs_to_object).should_not be_true
|
56
56
|
end
|
57
|
-
|
57
|
+
|
58
58
|
it "should have its relationship cascade when sub-classed after the relationship is defined" do
|
59
59
|
TestResource.belongs_to :belongs_to_object
|
60
60
|
class ChildTestResource2 < TestResource; end
|
61
61
|
ChildTestResource2.association?(:belongs_to_object).should be true
|
62
62
|
end
|
63
|
-
|
63
|
+
|
64
64
|
context "Determining associated classes with a namespace" do
|
65
|
-
|
65
|
+
|
66
66
|
it "should be able to find classes for associations that exist in the same module without a namespace" do
|
67
67
|
TestMod::TestClass.belongs_to :test_association
|
68
68
|
TestMod::TestClass.association_class_name(:test_association).should eql("TestMod::TestAssociation")
|
69
69
|
end
|
70
|
-
|
70
|
+
|
71
71
|
it "should be return a regular class name for a class defined at the root level" do
|
72
72
|
TestMod::TestClass.belongs_to :belongs_to_object
|
73
73
|
TestMod::TestClass.association_class_name(:belongs_to_object).should eql("BelongsToObject")
|
74
74
|
end
|
75
|
-
|
75
|
+
|
76
76
|
it "should work for a class name specified with a namespace module" do
|
77
77
|
TestMod::TestClass.belongs_to :nonsense, :class_name => "TestMod::TestAssociation"
|
78
78
|
TestMod::TestClass.association_class_name(:nonsense).should eql("TestMod::TestAssociation")
|
79
79
|
end
|
80
|
-
|
80
|
+
|
81
81
|
it "should work for nested module as well" do
|
82
82
|
TestMod::InnerMod::InnerClass.belongs_to :test_association
|
83
83
|
TestMod::InnerMod::InnerClass.association_class_name(:test_association).should eql("TestMod::TestAssociation")
|
84
84
|
end
|
85
|
-
|
85
|
+
|
86
86
|
it "should prefer to find classes within similar modules to ones in the root namespace" do
|
87
87
|
TestMod::InnerMod::InnerClass.belongs_to :test_resource
|
88
88
|
TestMod::InnerMod::InnerClass.association_class_name(:test_resource).should eql("TestMod::TestResource")
|
89
89
|
end
|
90
|
-
|
90
|
+
|
91
91
|
it "should be able to override into the root namespace by prefixing with ::" do
|
92
92
|
TestMod::InnerMod::InnerClass.belongs_to :test_resource, :class_name => "::TestResource"
|
93
93
|
TestMod::InnerMod::InnerClass.association_class_name(:test_resource).should eql("::TestResource")
|
94
94
|
end
|
95
|
-
|
95
|
+
|
96
96
|
end
|
97
|
-
|
98
|
-
|
97
|
+
|
98
|
+
|
99
99
|
end
|
100
|
-
|
100
|
+
|
101
101
|
context "Remote Definitions" do
|
102
|
-
|
102
|
+
|
103
103
|
before(:all) do
|
104
104
|
TestResource.reload_class_attributes
|
105
105
|
end
|
106
|
-
|
106
|
+
|
107
107
|
it "should be able define an association remotely" do
|
108
108
|
TestResource.belongs_to?(:belongs_to_object).should be true
|
109
109
|
TestResource.new.belongs_to_object.klass.should eql BelongsToObject
|
@@ -113,19 +113,19 @@ describe "Associations" do
|
|
113
113
|
TestResource.belongs_to?(:custom_name).should be true
|
114
114
|
TestResource.new.custom_name.klass.should eql BelongsToObject
|
115
115
|
end
|
116
|
-
|
116
|
+
|
117
117
|
end
|
118
|
-
|
119
|
-
|
118
|
+
|
119
|
+
|
120
120
|
context "creating and testing for scopes" do
|
121
|
-
|
121
|
+
|
122
122
|
it "should be able to define scopes which require class names" do
|
123
123
|
lambda {
|
124
124
|
TestResource.scope :test_scope
|
125
125
|
}.should raise_error
|
126
126
|
TestResource.scope :test_scope, {:has_many_objects => "test"}
|
127
127
|
end
|
128
|
-
|
128
|
+
|
129
129
|
it "should be able to test if a scope exists" do
|
130
130
|
TestResource.scope :test_scope, {:item => "test"}
|
131
131
|
TestResource.scope?(:test_scope).should be_true
|
@@ -149,66 +149,66 @@ describe "Associations" do
|
|
149
149
|
Scope2Class.scope?(:two).should be true
|
150
150
|
|
151
151
|
end
|
152
|
-
|
152
|
+
|
153
153
|
end
|
154
|
-
|
154
|
+
|
155
155
|
context "testing for scopes and associations on an instance" do
|
156
|
-
|
156
|
+
|
157
157
|
it "should be able to define associations on a class and test for them on an instance" do
|
158
158
|
TestResource.has_many :has_many_objects, :class_name => :other_has_many_objects
|
159
159
|
tst = TestResource.new
|
160
160
|
tst.has_many?(:has_many_objects).should be_true
|
161
161
|
tst.has_many_class_name(:has_many_objects).should eql("OtherHasManyObject")
|
162
162
|
end
|
163
|
-
|
163
|
+
|
164
164
|
it "should be able to define scopes on a class and test for them on an instance" do
|
165
165
|
TestResource.scope :has_many_objects, {:item => "test"}
|
166
166
|
tst = TestResource.new
|
167
167
|
tst.scope?(:has_many_objects).should be_true
|
168
168
|
tst.scope_attributes(:has_many_objects).should eql({"item" => "test"})
|
169
169
|
end
|
170
|
-
|
170
|
+
|
171
171
|
end
|
172
|
-
|
172
|
+
|
173
173
|
describe "Single Object Associations" do
|
174
|
-
|
174
|
+
|
175
175
|
before(:all) do
|
176
176
|
TestResource.reload_class_attributes
|
177
177
|
end
|
178
|
-
|
178
|
+
|
179
179
|
after(:all) do
|
180
180
|
TestResource.reload_class_attributes
|
181
181
|
end
|
182
|
-
|
182
|
+
|
183
183
|
it "should return nil if its internal object is nil" do
|
184
184
|
ap = Associations::SingleObjectProxy.new("TestResource", {})
|
185
185
|
ap.instance_variable_set(:@internal_object, nil)
|
186
186
|
ap.blank?.should be_true
|
187
187
|
end
|
188
|
-
|
188
|
+
|
189
189
|
it "should not throw an error on serializable hash if its internal object is nil" do
|
190
190
|
ap = Associations::SingleObjectProxy.new("TestResource", {})
|
191
191
|
ap.instance_variable_set(:@internal_object, nil)
|
192
192
|
lambda {ap.serializable_hash}.should_not raise_error
|
193
193
|
end
|
194
|
-
|
194
|
+
|
195
195
|
it "should be able to create a SingleObjectProxy around a blank hash" do
|
196
196
|
ap = Associations::SingleObjectProxy.new("TestResource", {})
|
197
197
|
ap.remote_path.should be_blank
|
198
198
|
end
|
199
|
-
|
199
|
+
|
200
200
|
it "should be able to extract a service uri from the contents hash" do
|
201
201
|
ap = Associations::SingleObjectProxy.new("TestResource",{:service_uri => "/path"})
|
202
202
|
ap.remote_path.should eql("/path")
|
203
203
|
end
|
204
|
-
|
204
|
+
|
205
205
|
it "should be able to recognize the attributes of an object and not make them scopes" do
|
206
206
|
TestResource.define_attributes :test
|
207
207
|
ap = Associations::SingleObjectProxy.new("TestResource",{:service_uri => "/path", :test => "testval"})
|
208
208
|
ap.scope?("test").should be_false
|
209
209
|
ap.remote_path.should eql("/path")
|
210
210
|
end
|
211
|
-
|
211
|
+
|
212
212
|
it "should make all attributes except the service uri into scopes given the scopes_only option" do
|
213
213
|
ap = Associations::SingleObjectProxy.new("TestResource",{:service_uri => "/path", :test_scope => {"testval" => true}, :scopes_only => true})
|
214
214
|
ap.scope?("test_scope").should be_true
|
@@ -221,7 +221,7 @@ describe "Associations" do
|
|
221
221
|
ap.internal_object.attributes.keys.should include("test")
|
222
222
|
end
|
223
223
|
end
|
224
|
-
|
224
|
+
|
225
225
|
describe "Multi Object Associations" do
|
226
226
|
|
227
227
|
before(:all) do
|
@@ -297,24 +297,29 @@ describe "Associations" do
|
|
297
297
|
end
|
298
298
|
|
299
299
|
describe "Selecting scopes" do
|
300
|
-
|
300
|
+
|
301
301
|
before(:all) do
|
302
302
|
ScopeResource.class_eval do
|
303
|
-
scope :
|
304
|
-
scope :
|
305
|
-
scope :
|
303
|
+
scope :no_arg, {}
|
304
|
+
scope :one_arg, {:id => :req}
|
305
|
+
scope :one_array_arg, {:ids => :req}
|
306
|
+
scope :two_args, {:page => :req, :per_page => :req}
|
307
|
+
scope :opt_args, {:arg1 => :opt}
|
308
|
+
scope :var_args, {:ids => :rest}
|
309
|
+
scope :mix_args, {:id => :req, :vararg => :rest}
|
306
310
|
end
|
307
311
|
end
|
308
|
-
|
309
|
-
|
312
|
+
|
310
313
|
it "should be able to query scopes on the current model" do
|
311
|
-
ScopeResource.
|
312
|
-
ScopeResource.
|
313
|
-
ScopeResource.
|
314
|
-
|
315
|
-
ScopeResource.
|
314
|
+
ScopeResource.no_arg.to_query.should eql "no_arg=true"
|
315
|
+
# ScopeResource.one_arg(5).to_query.should eql "one_arg[id]=5"
|
316
|
+
# ScopeResource.one_array_arg([3, 5]).to_query.should eql "one_array_arg[ids][]=3&one_array_arg[ids][]=5"
|
317
|
+
# ScopeResource.two_args(1, 20).to_query.should eql "two_args[page]=1&two_args[per_page]=20"
|
318
|
+
# ScopeResource.opt_arg.to_query.should eql "opt_args=true"
|
319
|
+
# ScopeResource.opt_args(3).to_query.should eql "opt_args[arg1]=3"
|
320
|
+
# ScopeResource.var_args(1, 2).to_query.should eql "var_args[ids][]=1&var_args[ids][]=2"
|
321
|
+
# ScopeResource.mix_args("a", {:opt1 => 1}, {:opt2 => 2}).to_query.should eql "mix_args[arg1]=a&mix_args[vararg][][opt1]=1&mix_arg[vararg][][opt2]=2"
|
316
322
|
end
|
317
|
-
|
318
323
|
|
319
324
|
it "should be able to change scopes" do
|
320
325
|
ap = Associations::MultiObjectProxy.new("TestResource", [{:service_uri => "/route", :scope1 => {"scope1" => true}, :scope2 => {"scope2" => true}}])
|
@@ -327,17 +332,17 @@ describe "Associations" do
|
|
327
332
|
ap.scope1.scope2.current_scope.scope1_and_scope2_scope?.should be_true
|
328
333
|
ap.scope1.scope2.to_query.should eql("scope1=true&scope2=true")
|
329
334
|
end
|
330
|
-
|
335
|
+
|
331
336
|
it "should support scopes that contain underscores" do
|
332
337
|
ap = Associations::MultiObjectProxy.new("TestResource", [{:service_uri => "/route", :scope_1 => {"scope_1" => true}, :scope_2 => {"scope_2" => true}}])
|
333
338
|
ap.scope_1.scope_2.current_scope.scope_1_and_scope_2_scope?.should be_true
|
334
339
|
end
|
335
|
-
|
340
|
+
|
336
341
|
it "should be able to return the current query string" do
|
337
342
|
ap = Associations::MultiObjectProxy.new("TestResource", [{:service_uri => "/route", :scope_1 => {"scope_1" => true}, :scope_2 => {"scope_2" => true}}])
|
338
343
|
ap.scope_1.scope_2.to_query.should eql("scope_1=true&scope_2=true")
|
339
344
|
end
|
340
|
-
|
345
|
+
|
341
346
|
it "should be able to substitute values into the scope query strings by passing a hash to the methods" do
|
342
347
|
ap = Associations::MultiObjectProxy.new("TestResource", [{:service_uri => "/route", :scope_1 => {"scope_1" => true, :test_sub => false}, :scope_2 => {"scope_2" => true}}])
|
343
348
|
obj = ap.scope_1(:test_sub => true).scope_2
|
@@ -347,15 +352,15 @@ describe "Associations" do
|
|
347
352
|
|
348
353
|
|
349
354
|
end
|
350
|
-
|
355
|
+
|
351
356
|
describe "Loading and Caching loaded data" do
|
352
|
-
|
357
|
+
|
353
358
|
context "Single Object" do
|
354
|
-
|
359
|
+
|
355
360
|
before(:all) do
|
356
361
|
TestResource.reload_class_attributes
|
357
362
|
end
|
358
|
-
|
363
|
+
|
359
364
|
it "should be able to force load an object" do
|
360
365
|
ap = Associations::SingleObjectProxy.new("TestResource",{:service_uri => '/single_object_association', :active => {:active => true}, :scopes_only => true})
|
361
366
|
ap.loaded.should be_blank
|
@@ -365,7 +370,7 @@ describe "Associations" do
|
|
365
370
|
# Make sure it isn't reloaded
|
366
371
|
ap.name.should eql(name)
|
367
372
|
end
|
368
|
-
|
373
|
+
|
369
374
|
it "should be able to load a scope" do
|
370
375
|
ap = Associations::SingleObjectProxy.new("TestResource",{:service_uri => '/single_object_association', :active => {:active => true}, :scopes_only => true})
|
371
376
|
ap.internal_object.active.should be_false
|
@@ -377,7 +382,7 @@ describe "Associations" do
|
|
377
382
|
# another check that the resource wasn't reloaded
|
378
383
|
ap.times_loaded.should eql(2)
|
379
384
|
end
|
380
|
-
|
385
|
+
|
381
386
|
it "should be able to load a chain of scopes" do
|
382
387
|
ap = Associations::SingleObjectProxy.new("TestResource",{:service_uri => '/single_object_association', :active => {:active => true}, :with_birthday => {:birthday => true}, :scopes_only => true})
|
383
388
|
first = ap.active.with_birthday.id
|
@@ -385,36 +390,42 @@ describe "Associations" do
|
|
385
390
|
ap.times_loaded.should eql(1)
|
386
391
|
ap.active.with_birthday.birthday.should_not be_blank
|
387
392
|
end
|
388
|
-
|
393
|
+
|
389
394
|
it "should proxy unknown methods to the object loading if it hasn't already" do
|
390
395
|
ap = Associations::SingleObjectProxy.new("TestResource",{:service_uri => '/single_object_association', :active => {:active => false}, :with_birthday => {:birthday => true}, :scopes_only => true})
|
391
396
|
ap.times_loaded.should eql(0)
|
392
397
|
ap.id.should_not be_blank
|
393
398
|
ap.times_loaded.should eql(1)
|
394
399
|
end
|
395
|
-
|
400
|
+
|
396
401
|
it "should load scopes with caching" do
|
397
|
-
ap = Associations::SingleObjectProxy.new("TestResource",{:service_uri => '/single_object_association', :active => {:active =>
|
402
|
+
ap = Associations::SingleObjectProxy.new("TestResource",{:service_uri => '/single_object_association', :active => {:active => true}, :scopes_only => true})
|
398
403
|
ap.times_loaded.should eql(0)
|
399
|
-
ap.active(
|
404
|
+
ap.active.expires_in(30).internal_object
|
405
|
+
ap.active.expires_in(30).internal_object
|
400
406
|
ap.times_loaded.should eql(1)
|
401
|
-
ap.active(:active => true, :expires_in => 10).ttl.should eql(10)
|
402
407
|
end
|
403
|
-
|
408
|
+
|
409
|
+
it "should check that ttl matches the expiration parameter" do
|
410
|
+
ap = Associations::SingleObjectProxy.new("TestResource",{:service_uri => '/single_object_association', :active => {:active => true}, :scopes_only => true})
|
411
|
+
ap.active.expires_in(10).ttl.should eql(10)
|
412
|
+
end
|
413
|
+
|
404
414
|
it "should cache scopes when caching enabled" do
|
405
415
|
ap = Associations::SingleObjectProxy.new("TestResource",{:service_uri => '/single_object_association', :active => {:active => false}, :with_birthday => {:birthday => true}, :scopes_only => true})
|
406
416
|
ApiResource.expects(:with_ttl).with(10)
|
407
417
|
ap.active(:active => true, :expires_in => 10).internal_object
|
408
418
|
end
|
409
|
-
|
419
|
+
|
410
420
|
it "should only load each distinct set of scopes once" do
|
411
421
|
ap = Associations::SingleObjectProxy.new("TestResource",{:service_uri => '/single_object_association', :active => {:active => false}, :with_birthday => {:birthday => true}, :scopes_only => true})
|
412
422
|
ap.times_loaded.should eql(0)
|
413
|
-
ap.active
|
414
|
-
ap.with_birthday.
|
423
|
+
ap.active.with_birthday.internal_object
|
424
|
+
ap.active.with_birthday.internal_object
|
425
|
+
ap.with_birthday.active.internal_object
|
415
426
|
ap.times_loaded.should eql(1)
|
416
427
|
end
|
417
|
-
|
428
|
+
|
418
429
|
it "should be able to clear it's loading cache" do
|
419
430
|
ap = Associations::SingleObjectProxy.new("TestResource",{:service_uri => '/single_object_association', :active => {:active => true}, :with_birthday => {:birthday => true}, :scopes_only => true})
|
420
431
|
ap.active.internal_object
|
@@ -423,7 +434,7 @@ describe "Associations" do
|
|
423
434
|
ap.active.internal_object
|
424
435
|
ap.times_loaded.should eql(1)
|
425
436
|
end
|
426
|
-
|
437
|
+
|
427
438
|
end
|
428
439
|
|
429
440
|
it "should be able to reload a single-object association" do
|
@@ -454,44 +465,44 @@ describe "Associations" do
|
|
454
465
|
|
455
466
|
ap.first.name.should eql old_name
|
456
467
|
end
|
457
|
-
|
468
|
+
|
458
469
|
context "Multi Object" do
|
459
|
-
|
470
|
+
|
460
471
|
it "should be able to load 'all'" do
|
461
472
|
ap = Associations::MultiObjectProxy.new("TestResource",{:service_uri => '/multi_object_association', :active => {:active => false}, :inactive => {:active => false}, :with_birthday => {:birthday => true}})
|
462
473
|
results = ap.all
|
463
474
|
results.size.should eql(5)
|
464
475
|
results.first.active.should be_false
|
465
476
|
end
|
466
|
-
|
477
|
+
|
467
478
|
it "should be able to load a scope" do
|
468
479
|
ap = Associations::MultiObjectProxy.new("TestResource",{:service_uri => '/multi_object_association', :active => {:active => false}, :inactive => {:active => false}, :with_birthday => {:birthday => true}})
|
469
480
|
results = ap.active.internal_object
|
470
481
|
results.size.should eql(5)
|
471
482
|
results.first.active.should be_true
|
472
483
|
end
|
473
|
-
|
484
|
+
|
474
485
|
it "should be able to load a chain of scopes" do
|
475
486
|
ap = Associations::MultiObjectProxy.new("TestResource",{:service_uri => '/multi_object_association', :active => {:active => true}, :inactive => {:active => false}, :with_birthday => {:birthday => true}})
|
476
487
|
results = ap.active.with_birthday.internal_object
|
477
488
|
results.first.active.should be_true
|
478
489
|
results.first.birthday.should_not be_blank
|
479
490
|
end
|
480
|
-
|
491
|
+
|
481
492
|
it "should be able to load a chain of scopes with substitution" do
|
482
493
|
ap = Associations::MultiObjectProxy.new("TestResource",{:service_uri => '/multi_object_association', :active => {:active => true}, :inactive => {:active => false}, :with_birthday => {:birthday => true}})
|
483
494
|
results = ap.inactive(:active => true).with_birthday.internal_object
|
484
495
|
results.first.active.should be_true
|
485
496
|
results.first.birthday.should_not be_blank
|
486
497
|
end
|
487
|
-
|
498
|
+
|
488
499
|
it "should proxy unknown methods to the object array loading if it hasn't already" do
|
489
500
|
ap = Associations::MultiObjectProxy.new("TestResource",{:service_uri => '/multi_object_association', :active => {:active => true}, :inactive => {:active => false}, :with_birthday => {:birthday => true}})
|
490
501
|
ap.first.should be_a TestResource
|
491
502
|
ap.active.first.should be_a TestResource
|
492
503
|
ap.times_loaded.should eql(2)
|
493
504
|
end
|
494
|
-
|
505
|
+
|
495
506
|
it "should only load each distinct set of scopes once" do
|
496
507
|
ap = Associations::MultiObjectProxy.new("TestResource",{:service_uri => '/multi_object_association', :active => {:active => true}, :inactive => {:active => false}, :with_birthday => {:birthday => true}})
|
497
508
|
ap.first
|
@@ -503,7 +514,7 @@ describe "Associations" do
|
|
503
514
|
ap.with_birthday.active.first
|
504
515
|
ap.times_loaded.should eql(3)
|
505
516
|
end
|
506
|
-
|
517
|
+
|
507
518
|
it "should be able to clear it's loading cache" do
|
508
519
|
ap = Associations::MultiObjectProxy.new("TestResource",{:service_uri => '/multi_object_association', :active => {:active => true}, :inactive => {:active => false}, :with_birthday => {:birthday => true}})
|
509
520
|
ap.active.first
|
@@ -512,38 +523,38 @@ describe "Associations" do
|
|
512
523
|
ap.active.first
|
513
524
|
ap.times_loaded.should eql(1)
|
514
525
|
end
|
515
|
-
|
526
|
+
|
516
527
|
it "should be enumerable" do
|
517
528
|
ap = Associations::MultiObjectProxy.new("TestResource",{:service_uri => '/multi_object_association', :active => {:active => true}, :inactive => {:active => false}, :with_birthday => {:birthday => true}})
|
518
529
|
ap.each do |tr|
|
519
530
|
tr.name.should_not be_blank
|
520
531
|
end
|
521
532
|
end
|
522
|
-
|
533
|
+
|
523
534
|
end
|
524
|
-
|
535
|
+
|
525
536
|
context "Scopes" do
|
526
|
-
|
537
|
+
|
527
538
|
before(:all) do
|
528
539
|
TestResource.reload_class_attributes
|
529
540
|
end
|
530
|
-
|
541
|
+
|
531
542
|
it "should define class methods for the known scopes" do
|
532
543
|
TestResource.scopes.each do |key, _|
|
533
544
|
TestResource.should respond_to key
|
534
545
|
end
|
535
546
|
end
|
536
|
-
|
547
|
+
|
537
548
|
it "should return a ResourceScope when calling any scope on a class" do
|
538
549
|
TestResource.send(TestResource.scopes.first.first.to_sym).should be_a Associations::ResourceScope
|
539
550
|
end
|
540
|
-
|
551
|
+
|
541
552
|
it "should be able to chain scopes" do
|
542
553
|
scp = TestResource.active.paginate
|
543
554
|
scp.should be_a Associations::ResourceScope
|
544
|
-
scp.to_query.should eql("active=true&
|
555
|
+
scp.to_query.should eql("active=true&paginate=true")
|
545
556
|
end
|
546
|
-
|
557
|
+
|
547
558
|
it "should load when calling all" do
|
548
559
|
TestResource.active.should respond_to :all
|
549
560
|
TestResource.active.should respond_to :internal_object
|
@@ -554,14 +565,14 @@ describe "Associations" do
|
|
554
565
|
res.should be_a TestResource
|
555
566
|
end
|
556
567
|
end
|
557
|
-
|
568
|
+
|
558
569
|
it "should load when calling an enumerable method or an array method" do
|
559
570
|
TestResource.active.each do |result|
|
560
571
|
result.should be_a TestResource
|
561
572
|
end
|
562
573
|
end
|
563
574
|
end
|
564
|
-
|
575
|
+
|
565
576
|
context "Assigning Data" do
|
566
577
|
context "Single Object Association" do
|
567
578
|
before(:all) do
|
@@ -571,25 +582,25 @@ describe "Associations" do
|
|
571
582
|
after(:all) do
|
572
583
|
TestResource.reload_class_attributes
|
573
584
|
end
|
574
|
-
|
585
|
+
|
575
586
|
it "should assign associations to the correct type on initialization" do
|
576
587
|
#binding.pry
|
577
588
|
tr = TestResource.new(:has_one_object => {:name => "Dan"}, :belongs_to_object => {:name => "Dan"})
|
578
|
-
|
589
|
+
|
579
590
|
tr.has_one_object.internal_object.should be_instance_of HasOneObject
|
580
591
|
tr.belongs_to_object.internal_object.should be_instance_of BelongsToObject
|
581
|
-
|
592
|
+
|
582
593
|
end
|
583
|
-
|
594
|
+
|
584
595
|
it "should assign associations to the correct type when setting attributes directly" do
|
585
596
|
tr = TestResource.new()
|
586
597
|
tr.has_one_object = {:name => "Dan"}
|
587
598
|
tr.belongs_to_object = {:name => "Dan"}
|
588
|
-
|
599
|
+
|
589
600
|
tr.has_one_object.internal_object.should be_instance_of HasOneObject
|
590
601
|
tr.belongs_to_object.internal_object.should be_instance_of BelongsToObject
|
591
602
|
end
|
592
|
-
|
603
|
+
|
593
604
|
it "should be able to reload a single-object association" do
|
594
605
|
ApiResource::Associations::SingleObjectProxy.any_instance.stubs(:remote_path => "/has_one_objects")
|
595
606
|
HasOneObject.connection.stubs(:get => nil)
|
@@ -599,12 +610,11 @@ describe "Associations" do
|
|
599
610
|
tr.has_one_object = {:color => "Blue"}
|
600
611
|
|
601
612
|
tr.has_one_object.reload
|
602
|
-
|
603
|
-
tr.has_one_object.should be_blank
|
613
|
+
tr.has_one_object.instance_variable_get(:@internal_object).should be_blank
|
604
614
|
end
|
605
|
-
|
615
|
+
|
606
616
|
end
|
607
|
-
|
617
|
+
|
608
618
|
context "Multi Object Association" do
|
609
619
|
before(:all) do
|
610
620
|
TestResource.has_many(:has_many_objects)
|
@@ -612,19 +622,19 @@ describe "Associations" do
|
|
612
622
|
after(:all) do
|
613
623
|
TestResource.reload_class_attributes
|
614
624
|
end
|
615
|
-
|
625
|
+
|
616
626
|
it "should assign associations to the correct type on initialization" do
|
617
627
|
tr = TestResource.new(:has_many_objects => [{:name => "Dan"}])
|
618
628
|
tr.has_many_objects.internal_object.first.should be_instance_of HasManyObject
|
619
|
-
|
629
|
+
|
620
630
|
end
|
621
|
-
|
631
|
+
|
622
632
|
it "should assign associations to the correct type when setting attributes directly" do
|
623
633
|
tr = TestResource.new()
|
624
634
|
tr.has_many_objects = [{:name => "Dan"}]
|
625
635
|
tr.has_many_objects.internal_object.first.should be_instance_of HasManyObject
|
626
636
|
end
|
627
|
-
|
637
|
+
|
628
638
|
it "should be able to reload a multi-object association" do
|
629
639
|
ApiResource::Associations::MultiObjectProxy.any_instance.stubs(:remote_path => "/has_many_objects")
|
630
640
|
ApiResource::Connection.any_instance.stubs(:get => [])
|
@@ -637,7 +647,7 @@ describe "Associations" do
|
|
637
647
|
end
|
638
648
|
|
639
649
|
end
|
640
|
-
|
650
|
+
|
641
651
|
context "ActiveModel" do
|
642
652
|
before(:all) do
|
643
653
|
require 'active_record'
|
@@ -6,6 +6,7 @@ Mocks.define do
|
|
6
6
|
get(HashDealer.roll(:test_association_resource), :params => {})
|
7
7
|
get(HashDealer.roll(:active_test_association_resource), :params => {:active => true})
|
8
8
|
get(HashDealer.roll(:active_birthday_test_association_resource), :params => {:active => true, :birthday => true})
|
9
|
+
get(HashDealer.roll(:inactive_birthday_test_association_resource), :params => {:active => false, :birthday => true})
|
9
10
|
end
|
10
11
|
|
11
12
|
endpoint("/mock_with_block/:id") do
|
@@ -59,4 +60,4 @@ Mocks.define do
|
|
59
60
|
get({})
|
60
61
|
end
|
61
62
|
|
62
|
-
end
|
63
|
+
end
|
@@ -13,11 +13,19 @@ HashDealer.define(:active_birthday_test_association_resource, :parent => :active
|
|
13
13
|
birthday{Date.today}
|
14
14
|
end
|
15
15
|
|
16
|
+
HashDealer.define(:inactive_test_association_resource, :parent => :test_association_resource) do
|
17
|
+
active(false)
|
18
|
+
end
|
19
|
+
|
20
|
+
HashDealer.define(:inactive_birthday_test_association_resource, :parent => :inactive_test_association_resource) do
|
21
|
+
birthday{Date.today}
|
22
|
+
end
|
23
|
+
|
16
24
|
HashDealer.define(:has_one_object) do
|
17
|
-
|
18
|
-
|
25
|
+
size("large")
|
26
|
+
color("blue")
|
19
27
|
end
|
20
28
|
|
21
29
|
HashDealer.define(:has_many_object) do
|
22
|
-
|
23
|
-
end
|
30
|
+
name("name")
|
31
|
+
end
|
@@ -4,8 +4,8 @@ HashDealer.define(:new_test_object) do
|
|
4
4
|
:public => [:name, :age, :is_active, [:bday, :date], [:roles, :array]]
|
5
5
|
})
|
6
6
|
scopes({
|
7
|
-
:active => {:active =>
|
8
|
-
:paginate => {:
|
7
|
+
:active => {:active => :opt},
|
8
|
+
:paginate => {:per_page => :opt, :current_page => :opt}
|
9
9
|
})
|
10
10
|
associations({
|
11
11
|
:has_many => {:has_many_objects => {}},
|
@@ -35,4 +35,4 @@ HashDealer.define(:test_resource_errors) do
|
|
35
35
|
:name => ["can't be blank"],
|
36
36
|
:age => ["must be a valid number"]
|
37
37
|
})
|
38
|
-
end
|
38
|
+
end
|