api_resource 0.6.18 → 0.6.19

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.
@@ -0,0 +1,264 @@
1
+ module ApiResource
2
+
3
+ #
4
+ # Handles serialization for a given instance of ApiResource::Base with
5
+ # a set of options
6
+ #
7
+ # @author [dlangevin]
8
+ #
9
+ class Serializer
10
+
11
+ # @!attribute [r] options
12
+ # @return [HashWithIndifferentAccess]
13
+ attr_reader :options
14
+
15
+ # @!attribute [r] record
16
+ # @return [ApiResource::Base]
17
+ attr_reader :record
18
+
19
+ #
20
+ # Constructor
21
+ #
22
+ # @param record [ApiResource::Base] Record to serialize
23
+ # @param options = {} [Hash] Options supplied
24
+ #
25
+ # @option options [Array<Symbol,String>] except (Array<>) Attributes to
26
+ # explicitly exclude
27
+ # @option options [Array<Symbol,String] include_associations (Array<>)
28
+ # Associations to explicitly include
29
+ # @option options [Array<Symbol,String] include_extras (Array<>)
30
+ # Attributes to explicitly include
31
+ # @option options [Boolean] include_id (false) Whether or not to include
32
+ # the primary key
33
+ # @option options [Boolean] include_nil_attributes (false) Whether or not
34
+ # to include attributes that are blank/nil in the serialized hash
35
+ #
36
+ def initialize(record, options = {})
37
+ @record = record
38
+ @options = options.with_indifferent_access
39
+ end
40
+
41
+ #
42
+ # Return our serialized object as a Hash
43
+ #
44
+ # @return [HashWithIndifferentAccess]
45
+ def to_hash
46
+ ret = HashWithIndifferentAccess.new
47
+ ret.merge!(self.attributes_for_hash)
48
+ ret.merge!(self.associations_for_hash)
49
+ ret.merge!(self.add_on_data_for_hash)
50
+ ret.merge!(self.association_foreign_keys_for_hash)
51
+ ret
52
+ end
53
+
54
+
55
+ protected
56
+
57
+ #
58
+ # Data that is implicitly or explicitly added by options
59
+ #
60
+ # @return [Hash] Data to add on
61
+ def add_on_data_for_hash
62
+ {}.tap do |ret|
63
+ # explicit inclusion of the record's id (used in nested updates)
64
+ if self.options[:include_id] && !self.record.new_record?
65
+ ret[:id] = self.record.id
66
+ end
67
+ end
68
+ end
69
+
70
+ #
71
+ # Attribute data to include in the hash - this checks whether or not
72
+ # to include a given attribute with {#include_attribute?}
73
+ #
74
+ # @return [Hash] Data from attributes
75
+ def attributes_for_hash
76
+ self.record.attributes.inject({}) do |accum, (key,val)|
77
+ if self.include_attribute?(key, val)
78
+ accum.merge(key => val)
79
+ else
80
+ accum
81
+ end
82
+ end
83
+ end
84
+
85
+ #
86
+ # Data that is included due to foreign keys.
87
+ #
88
+ # @example
89
+ # tr = TestResource.new
90
+ # tr.belongs_to_object = BelongsToObject.find(10)
91
+ # Serializer.new(tr).to_hash #=> {:belongs_to_object_id => 10}
92
+ #
93
+ # @return [Hash] Data from foreign keys
94
+ def association_foreign_keys_for_hash
95
+ {}.tap do |ret|
96
+ self.record.association_names.each do |name|
97
+ # this is the method name
98
+ # E.g. :belongs_to_object => :belongs_to_object_id
99
+ method_name = self.record.class.association_foreign_key_field(name)
100
+ # make sure we have changes
101
+ next if self.record.changes[method_name].blank?
102
+ # make sure we aren't in a prefix method
103
+ next if self.is_prefix_field?(method_name)
104
+ # add the changed value
105
+ ret[method_name] = self.record.send(method_name)
106
+ end
107
+ end
108
+ end
109
+
110
+ #
111
+ # Nested association data for the hash. This checks whether or not
112
+ # to include a given association with {#include_association?}
113
+ #
114
+ # @return [Hash] Data from associations
115
+ def associations_for_hash
116
+ self.record.association_names.inject({}) do |accum, assoc_name|
117
+ if self.include_association?(assoc_name)
118
+ # get the association
119
+ assoc = self.record.send(assoc_name)
120
+ options = self.options.merge(include_id: true)
121
+ accum.merge(assoc_name => assoc.serializable_hash(options))
122
+ else
123
+ accum
124
+ end
125
+ end
126
+ end
127
+
128
+ #
129
+ # List of all association names that are in our changes set
130
+ #
131
+ # @return [Array<Symbol>]
132
+ def changed_associations
133
+ @changed_associations ||= begin
134
+ self.record.changes.keys.symbolize_array.select{ |k|
135
+ self.record.association?(k)
136
+ }
137
+ end
138
+ end
139
+
140
+ #
141
+ # Helper method to check if a blank value should be included
142
+ # in the response
143
+ #
144
+ # @param key [String, Symbol] Attribute name
145
+ # @param val [Mixed] Value to include
146
+ #
147
+ # @return [Boolean] Whether or not to include this key/value pair
148
+ def check_blank_value(key, val)
149
+ # if we explicitly want nil attributes
150
+ return true if self.options[:include_nil_attributes]
151
+ # or if the attribute has changed to nil
152
+ return true if self.record.changes[key].present?
153
+ # make sure our value isn't blank
154
+ return val.present?
155
+ end
156
+
157
+ #
158
+ # List of explicitly excluded attributes
159
+ #
160
+ # @return [type] [description]
161
+ def excluded_keys
162
+ @excluded_keys ||= begin
163
+ ret = self.options[:except] || []
164
+ ret.map(&:to_sym)
165
+ end
166
+ end
167
+
168
+ #
169
+ # Should we include this association in our hash?
170
+ #
171
+ # @param association [Symbol] Association name to check
172
+ #
173
+ # @return [Boolean] Whether or not to include it
174
+ def include_association?(association)
175
+ # if we have explicitly requested this association we include it
176
+ return true if self.included_associations.include?(association)
177
+ return true if self.changed_associations.include?(association)
178
+ # explicitly excluded
179
+ return false if self.excluded_keys.include?(association)
180
+ return false
181
+ end
182
+
183
+ #
184
+ # Should we include this attribute?
185
+ #
186
+ # @param attribute [String, Symbol] Field name
187
+ # @param val [Mixed] Field value
188
+ #
189
+ # @return [Boolean] Whether or not to include it
190
+ def include_attribute?(attribute, val)
191
+ attribute = attribute.to_sym
192
+ # explicitly included
193
+ return true if self.included_attributes.include?(attribute)
194
+ # explicitly excluded
195
+ return false if self.excluded_keys.include?(attribute)
196
+ # make sure it's public
197
+ return false unless self.public_attributes.include?(attribute)
198
+ # make sure it's not already accounted for in the URL
199
+ if self.is_prefix_field?(attribute)
200
+ return false
201
+ end
202
+ # check to make sure the value is something we want to send
203
+ return false unless self.check_blank_value(attribute, val)
204
+
205
+ # default to true
206
+ true
207
+ end
208
+
209
+ #
210
+ # Associations explicitly included by the caller
211
+ #
212
+ # @return [Array<Symbol>]
213
+ def included_associations
214
+ @included_associations ||= begin
215
+ self.options[:include_associations] ||= []
216
+ self.options[:include_associations].collect(&:to_sym)
217
+ end
218
+ end
219
+
220
+ #
221
+ # Attributes explicitly included by the caller
222
+ #
223
+ # @return [Array<Symbol>]
224
+ def included_attributes
225
+ @included_attributes ||= begin
226
+ ret = self.options[:include_extras] || []
227
+ ret.map(&:to_sym)
228
+ end
229
+ end
230
+
231
+ #
232
+ # Whether or not a given attribute is accounted for in the
233
+ # prefix for this class
234
+ #
235
+ # @param attribute [Symbol] Attribute to check
236
+ #
237
+ # @example
238
+ # class TestResource
239
+ # prefix '/belongs_to_objects/:id/test_resources'
240
+ # end
241
+ #
242
+ # tr = TestResource.new(:belongs_to_object_id => 10)
243
+ # Serializer.new(tr).to_hash #=> {}
244
+ #
245
+ # tr.save #=> makes a call to /belongs_to_objects/10/test_resources
246
+ #
247
+ # @return [Boolean]
248
+ def is_prefix_field?(attribute)
249
+ self.record.prefix_attribute_names.include?(attribute.to_sym)
250
+ end
251
+
252
+ #
253
+ # List of public attributes for the record
254
+ #
255
+ # @return [Array<Sumbol>]
256
+ def public_attributes
257
+ @public_attributes ||= begin
258
+ self.record.attributes.keys.symbolize_array.reject{ |k|
259
+ self.record.protected_attribute?(k)
260
+ }
261
+ end
262
+ end
263
+ end
264
+ end
@@ -5,6 +5,7 @@ require 'api_resource/typecasters/integer_typecaster'
5
5
  require 'api_resource/typecasters/string_typecaster'
6
6
  require 'api_resource/typecasters/time_typecaster'
7
7
  require 'api_resource/typecasters/array_typecaster'
8
+ require 'api_resource/typecasters/unknown_typecaster'
8
9
 
9
10
  # Apparently need to require the active_support class_attribute
10
11
  require 'active_support/core_ext/class/attribute'
@@ -12,6 +13,15 @@ require 'active_support/core_ext/class/attribute'
12
13
 
13
14
  module ApiResource
14
15
 
16
+ #
17
+ # Error raised when unable to find a typecaster for a given
18
+ # attribute
19
+ #
20
+ # @author [ejlangev]
21
+ #
22
+ class TypecasterNotFound < NoMethodError
23
+ end
24
+
15
25
  module Typecast
16
26
 
17
27
  extend ActiveSupport::Concern
@@ -64,9 +74,11 @@ module ApiResource
64
74
 
65
75
  def default_typecasters
66
76
  @default_typecasters ||= {
77
+ :array => ArrayTypecaster,
67
78
  :boolean => BooleanTypecaster,
68
79
  :bool => BooleanTypecaster,
69
80
  :date => DateTypecaster,
81
+ :datetime => TimeTypecaster,
70
82
  :decimal => FloatTypecaster,
71
83
  :float => FloatTypecaster,
72
84
  :integer => IntegerTypecaster,
@@ -74,8 +86,7 @@ module ApiResource
74
86
  :string => StringTypecaster,
75
87
  :text => StringTypecaster,
76
88
  :time => TimeTypecaster,
77
- :datetime => TimeTypecaster,
78
- :array => ArrayTypecaster,
89
+ :unknown => UnknownTypecaster
79
90
  }
80
91
  end
81
92
 
@@ -0,0 +1,33 @@
1
+ module ApiResource
2
+
3
+ module Typecast
4
+
5
+ # The unknown typecaster which does not modify the value of
6
+ # the attribute in either direction. Keeps the interface consistent
7
+ # for unspecified typecasters
8
+ #
9
+ # @author [ejlangev]
10
+ #
11
+ module UnknownTypecaster
12
+
13
+ #
14
+ # Just returns what was passed in
15
+ # @param value [Object] The value to typecast
16
+ #
17
+ # @return [Object] An unmodified value
18
+ def self.from_api(value)
19
+ return value
20
+ end
21
+
22
+ #
23
+ # Just returns what was passed in
24
+ # @param value [Object] The value to typecast
25
+ #
26
+ # @return [Object] An unmodified value
27
+ def self.to_api(value)
28
+ return value
29
+ end
30
+
31
+ end
32
+ end
33
+ end
@@ -1,3 +1,3 @@
1
1
  module ApiResource
2
- VERSION = "0.6.18"
2
+ VERSION = "0.6.19"
3
3
  end
@@ -2,15 +2,15 @@ require 'spec_helper'
2
2
 
3
3
  module ApiResource
4
4
  module Associations
5
-
5
+
6
6
  describe HasManyRemoteObjectProxy do
7
7
 
8
- before(:all) do
8
+ before(:each) do
9
9
  TestResource.reload_resource_definition
10
10
  end
11
11
 
12
12
  context "#<<" do
13
-
13
+
14
14
  it "implements the shift operator" do
15
15
  tr = TestResource.new
16
16
  tr.has_many_objects << HasManyObject.new
@@ -10,7 +10,7 @@ describe "Associations" do
10
10
 
11
11
  let(:ap) do
12
12
  res = Associations::SingleObjectProxy.new(
13
- "TestResource",
13
+ "TestResource",
14
14
  HasManyObject.new
15
15
  )
16
16
  res.internal_object = {
@@ -130,7 +130,7 @@ describe "Associations" do
130
130
 
131
131
  it "should be able to override into the root namespace by prefixing with ::" do
132
132
  TestMod::InnerMod::InnerClass.belongs_to :test_resource, :class_name => "::TestResource"
133
- TestMod::InnerMod::InnerClass.association_class_name(:test_resource).should eql("::TestResource")
133
+ TestMod::InnerMod::InnerClass.association_class_name(:test_resource).should eql("::TestResource")
134
134
  end
135
135
 
136
136
  end
@@ -170,7 +170,7 @@ describe "Associations" do
170
170
  TestResource.scope :test_scope, {:item => "test"}
171
171
  TestResource.scope?(:test_scope).should be_true
172
172
  TestResource.scope_attributes(:test_scope).should eql({"item" => "test"})
173
- end
173
+ end
174
174
 
175
175
  it "should not propagate scopes from one class to another" do
176
176
 
@@ -239,7 +239,7 @@ describe "Associations" do
239
239
 
240
240
  it "should be able to extract a service uri from the contents hash" do
241
241
  ap = Associations::SingleObjectProxy.new(
242
- "TestResource",
242
+ "TestResource",
243
243
  HasManyObject.new
244
244
  )
245
245
  ap.internal_object = {
@@ -248,12 +248,12 @@ describe "Associations" do
248
248
  ap.remote_path.should eql("/path")
249
249
  end
250
250
 
251
- it "should be able to recognize the attributes of an object
251
+ it "should be able to recognize the attributes of an object
252
252
  and not make them scopes" do
253
-
253
+
254
254
  TestResource.define_attributes :test
255
255
  ap = Associations::SingleObjectProxy.new(
256
- "TestResource",
256
+ "TestResource",
257
257
  HasManyObject.new
258
258
  )
259
259
 
@@ -329,7 +329,7 @@ describe "Associations" do
329
329
 
330
330
  it "should be able to recognize settings from a hash" do
331
331
  ap = Associations::MultiObjectProxy.new(
332
- "TestResource",
332
+ "TestResource",
333
333
  BelongsToObject
334
334
  )
335
335
  ap.internal_object = {:service_uri => "/route"}
@@ -338,7 +338,7 @@ describe "Associations" do
338
338
 
339
339
  it "should be able to recognize settings from a hash as a string" do
340
340
  ap = Associations::MultiObjectProxy.new(
341
- "TestResource",
341
+ "TestResource",
342
342
  BelongsToObject
343
343
  )
344
344
  ap.internal_object = {"service_uri" => "/route"}
@@ -348,22 +348,13 @@ describe "Associations" do
348
348
  it "should recognize settings with differing 'service_uri' names" do
349
349
  Associations::MultiObjectProxy.remote_path_element = :the_element
350
350
  ap = Associations::MultiObjectProxy.new(
351
- "TestResource",
351
+ "TestResource",
352
352
  BelongsToObject
353
353
  )
354
354
  ap.internal_object = {:the_element => "/route"}
355
355
  ap.remote_path.should eql("/route")
356
356
  end
357
357
 
358
- it "should include the foreign_key_id when saving" do
359
- tr = TestResource.new.tap do |tr|
360
- tr.stubs(:id => 123)
361
- end
362
- tr.has_many_object_ids = [4]
363
- hsh = tr.serializable_hash
364
- hsh[:has_many_object_ids].should eql([4])
365
- end
366
-
367
358
  it "should handle loading attributes from the remote" do
368
359
  tr = TestResource.instantiate_record({:has_many_object_ids => [3]})
369
360
  tr.has_many_object_ids.should eql([3])
@@ -379,51 +370,6 @@ describe "Associations" do
379
370
 
380
371
  end
381
372
 
382
- describe "Selecting scopes" do
383
-
384
- before(:all) do
385
- ScopeResource.class_eval do
386
- scope :no_arg, {}
387
- scope :one_arg, {:id => :req}
388
- scope :one_array_arg, {:ids => :req}
389
- scope :two_args, {:page => :req, :per_page => :req}
390
- scope :opt_args, {:arg1 => :opt}
391
- scope :var_args, {:ids => :rest}
392
- scope :mix_args, {:id => :req, :vararg => :rest}
393
- end
394
- end
395
-
396
- it "should be able to query scopes on the current model" do
397
- ScopeResource.no_arg.to_query.should eql(
398
- "no_arg=true"
399
- )
400
- ScopeResource.one_arg(5).to_query.should eql(
401
- "one_arg[id]=5"
402
- )
403
- ScopeResource.one_array_arg([3, 5]).to_query.should eql(
404
- "one_array_arg[ids][]=3&one_array_arg[ids][]=5"
405
- )
406
- ScopeResource.two_args(1, 20).to_query.should eql(
407
- "two_args[page]=1&two_args[per_page]=20"
408
- )
409
- $DEB = true
410
- ScopeResource.opt_args.to_query.should eql(
411
- "opt_args=true"
412
- )
413
- ScopeResource.opt_args(3).to_query.should eql(
414
- "opt_args[arg1]=3"
415
- )
416
- ScopeResource.var_args(1, 2).to_query.should eql(
417
- "var_args[ids][]=1&var_args[ids][]=2"
418
- )
419
- args = ["a", {:opt1 => 1}, {:opt2 => 2}]
420
- ScopeResource.mix_args(*args).to_query.should eql(
421
- "mix_args[id]=a&mix_args[vararg][][opt1]=1&mix_args[vararg][][opt2]=2"
422
- )
423
- end
424
- end
425
-
426
-
427
373
  end
428
374
 
429
375
  describe "Loading and Caching loaded data" do
@@ -452,7 +398,7 @@ describe "Associations" do
452
398
 
453
399
  it "should proxy unknown methods to the object loading if it hasn't already" do
454
400
  ap = Associations::SingleObjectProxy.new(
455
- "TestResource",
401
+ "TestResource",
456
402
  HasManyObject.new
457
403
  )
458
404
  ap.internal_object = {
@@ -465,7 +411,7 @@ describe "Associations" do
465
411
 
466
412
  it "should load scopes with caching" do
467
413
  ap = Associations::SingleObjectProxy.new(
468
- "TestResource",
414
+ "TestResource",
469
415
  HasManyObject.new
470
416
  )
471
417
  ap.internal_object = {
@@ -481,7 +427,7 @@ describe "Associations" do
481
427
 
482
428
  it "should check that ttl matches the expiration parameter" do
483
429
  ap = Associations::SingleObjectProxy.new(
484
- "TestResource",
430
+ "TestResource",
485
431
  HasManyObject.new
486
432
  )
487
433
  ap.internal_object = {
@@ -492,7 +438,7 @@ describe "Associations" do
492
438
 
493
439
  it "should cache scopes when caching enabled" do
494
440
  ap = Associations::SingleObjectProxy.new(
495
- "TestResource",
441
+ "TestResource",
496
442
  HasManyObject.new
497
443
  )
498
444
  ap.internal_object = {
@@ -503,7 +449,7 @@ describe "Associations" do
503
449
 
504
450
  it "should be able to clear it's loading cache" do
505
451
  ap = Associations::SingleObjectProxy.new(
506
- "TestResource",
452
+ "TestResource",
507
453
  HasManyObject.new
508
454
  )
509
455
  ap.internal_object = {
@@ -523,7 +469,7 @@ describe "Associations" do
523
469
 
524
470
  it "should be able to reload a single-object association" do
525
471
  ap = Associations::SingleObjectProxy.new(
526
- "TestResource",
472
+ "TestResource",
527
473
  HasManyObject.new
528
474
  )
529
475
  ap.internal_object = {
@@ -543,9 +489,9 @@ describe "Associations" do
543
489
  end
544
490
 
545
491
  it "should be able to reload a multi-object association" do
546
-
492
+
547
493
  ap = Associations::MultiObjectProxy.new(
548
- "TestResource",
494
+ "TestResource",
549
495
  BelongsToObject.new
550
496
  )
551
497
  ap.internal_object = {
@@ -568,7 +514,7 @@ describe "Associations" do
568
514
 
569
515
  it "should be able to load 'all'" do
570
516
  ap = Associations::MultiObjectProxy.new(
571
- "TestResource",
517
+ "TestResource",
572
518
  BelongsToObject.new
573
519
  )
574
520
  ap.internal_object = {
@@ -581,7 +527,7 @@ describe "Associations" do
581
527
 
582
528
  it "should be able to load a scope" do
583
529
  ap = Associations::MultiObjectProxy.new(
584
- "TestResource",
530
+ "TestResource",
585
531
  BelongsToObject.new
586
532
  )
587
533
  ap.internal_object = {
@@ -595,7 +541,7 @@ describe "Associations" do
595
541
 
596
542
  it "should be able to load a chain of scopes" do
597
543
  ap = Associations::MultiObjectProxy.new(
598
- "TestResource",
544
+ "TestResource",
599
545
  BelongsToObject.new
600
546
  )
601
547
  ap.internal_object = {
@@ -610,7 +556,7 @@ describe "Associations" do
610
556
  it "should be able to clear it's loading cache" do
611
557
 
612
558
  ap = Associations::MultiObjectProxy.new(
613
- "TestResource",
559
+ "TestResource",
614
560
  BelongsToObject.new
615
561
  )
616
562
  ap.internal_object = {
@@ -628,7 +574,7 @@ describe "Associations" do
628
574
 
629
575
  it "should be enumerable" do
630
576
  ap = Associations::MultiObjectProxy.new(
631
- "TestResource",
577
+ "TestResource",
632
578
  BelongsToObject.new
633
579
  )
634
580
  ap.internal_object = {
@@ -698,11 +644,11 @@ describe "Associations" do
698
644
  TestResource.reload_class_attributes
699
645
  end
700
646
 
701
- it "should assign associations to the correct
647
+ it "should assign associations to the correct
702
648
  type on initialization" do
703
-
649
+
704
650
  tr = TestResource.new(
705
- :has_one_object => {:color => "Blue"},
651
+ :has_one_object => {:color => "Blue"},
706
652
  :belongs_to_object => {:zip => "11201"},
707
653
  :has_many_objects => [{:name => "Dan"}]
708
654
  )
@@ -728,14 +674,14 @@ describe "Associations" do
728
674
  it "should assign associations to the correct type when setting attributes directly" do
729
675
  tr = TestResource.new()
730
676
  tr.has_one_object = {:name => "Dan"}
731
- tr.belongs_to_object = {:name => "Dan"}
677
+ tr.belongs_to_object = {:name => "Dan"}
732
678
 
733
679
  tr.has_one_object.internal_object.should be_instance_of HasOneObject
734
680
  tr.belongs_to_object.internal_object.should be_instance_of BelongsToObject
735
681
  end
736
682
 
737
683
  it "should be able to reload a single-object association" do
738
-
684
+
739
685
  tr = TestResource.new()
740
686
  tr.has_one_object = {:color => "Blue"}
741
687
 
@@ -766,7 +712,7 @@ describe "Associations" do
766
712
  end
767
713
 
768
714
  it "should be able to reload a multi-object association" do
769
-
715
+
770
716
  # do this to load the resource definition
771
717
  TestResource.reload_resource_definition
772
718
  HasManyObject.reload_resource_definition
@@ -778,7 +724,7 @@ describe "Associations" do
778
724
  tr.has_many_objects.should be_blank
779
725
  end
780
726
 
781
- it "should be able to override service_uri for a
727
+ it "should be able to override service_uri for a
782
728
  multi-object association" do
783
729
 
784
730
  tr = TestResource.new
@@ -788,7 +734,7 @@ describe "Associations" do
788
734
 
789
735
  end
790
736
 
791
- it "should be able to override service_uri for a multi-object
737
+ it "should be able to override service_uri for a multi-object
792
738
  association when loaded with instantiate_record" do
793
739
 
794
740
  tr = TestResource.instantiate_record(
@@ -804,17 +750,25 @@ describe "Associations" do
804
750
  before(:all) do
805
751
  require 'active_record'
806
752
  db_path = File.expand_path(File.dirname(__FILE__) + "/../tmp/api_resource_test_db.sqlite")
807
- ActiveRecord::Base.establish_connection({"adapter" => "sqlite3", "database" => db_path})
808
- ActiveRecord::Base.connection.create_table(:test_ars, :force => true) do |t|
809
- t.integer(:test_resource_id)
810
- end
753
+ # ActiveRecord::Base.establish_connection({"adapter" => "sqlite3", "database" => db_path})
754
+ # ActiveRecord::Base.connection.create_table(:test_ars, :force => true) do |t|
755
+ # t.integer(:test_resource_id)
756
+ # end
811
757
  ApiResource::Associations.activate_active_record
812
758
  TestAR = Class.new(ActiveRecord::Base)
813
- TestAR.class_eval do
759
+ TestAR.class_eval do
814
760
  belongs_to_remote :my_favorite_thing, :class_name => "TestClassYay"
815
761
  end
816
762
  HasManyObject.reload_resource_definition
817
763
  end
764
+
765
+ before(:each) do
766
+ TestAR.stubs(:columns).returns([])
767
+ TestAR.stubs(:connection).returns(
768
+ :schema_cache => stub(:table_exists => true)
769
+ )
770
+ end
771
+
818
772
  it "should define remote association types for AR" do
819
773
  [:has_many_remote, :belongs_to_remote, :has_one_remote].each do |assoc|
820
774
  ActiveRecord::Base.singleton_methods.should include assoc
@@ -835,7 +789,7 @@ describe "Associations" do
835
789
  end
836
790
  end
837
791
  context "Belongs To" do
838
- before(:all) do
792
+ before(:all) do
839
793
  TestAR.class_eval do
840
794
  belongs_to_remote :test_resource
841
795
  end
@@ -852,11 +806,12 @@ describe "Associations" do
852
806
  before(:all) do
853
807
  TestAR.class_eval do
854
808
  has_one_remote :test_resource
855
- has_one_remote :other_test_resource,
809
+ has_one_remote :other_test_resource,
856
810
  :class_name => "TestResource"
857
811
  end
858
812
  end
859
813
  it "should attempt to load a single remote object for a has_one relationship" do
814
+
860
815
  tar = TestAR.new
861
816
  tar.stubs(:id).returns(1)
862
817
  TestResource.connection.expects(:get)
@@ -907,8 +862,8 @@ describe "Associations" do
907
862
  end
908
863
  end
909
864
  context "Has Many Through" do
910
- before(:all) do
911
- TestAR.class_eval do
865
+ before(:all) do
866
+ TestAR.class_eval do
912
867
  self.extend ApiResource::Associations::HasManyThroughRemoteObjectProxy
913
868
  has_many :test_throughs
914
869
  has_many_through_remote(:belongs_to_objects, :through => :test_throughs)