api_resource 0.6.18 → 0.6.19

Sign up to get free protection for your applications and to get access to all the features.
@@ -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)