api_resource 0.6.21 → 0.6.22
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.
- checksums.yaml +4 -4
- data/.yardopts +1 -0
- data/Gemfile.lock +1 -1
- data/LICENSE.txt +22 -0
- data/README.md +16 -9
- data/docs/Attributes.md +64 -0
- data/docs/Caching.md +45 -0
- data/docs/GettingStarted.md +149 -0
- data/docs/Relationships.md +136 -0
- data/docs/ResourceDefinition.md +80 -0
- data/docs/Retrieval.md +279 -0
- data/docs/Serialization.md +56 -0
- data/lib/api_resource/associations/has_many_remote_object_proxy.rb +2 -2
- data/lib/api_resource/attributes.rb +16 -4
- data/lib/api_resource/base.rb +98 -19
- data/lib/api_resource/conditions/abstract_condition.rb +241 -129
- data/lib/api_resource/conditions/include_condition.rb +7 -1
- data/lib/api_resource/conditions/pagination_condition.rb +37 -0
- data/lib/api_resource/conditions/where_condition.rb +19 -0
- data/lib/api_resource/conditions.rb +18 -2
- data/lib/api_resource/connection.rb +27 -13
- data/lib/api_resource/exceptions.rb +11 -11
- data/lib/api_resource/finders/abstract_finder.rb +176 -95
- data/lib/api_resource/finders/multi_object_association_finder.rb +10 -9
- data/lib/api_resource/finders/resource_finder.rb +59 -49
- data/lib/api_resource/finders/single_finder.rb +5 -6
- data/lib/api_resource/finders/single_object_association_finder.rb +52 -51
- data/lib/api_resource/finders.rb +1 -1
- data/lib/api_resource/formats/file_upload_format.rb +75 -0
- data/lib/api_resource/formats.rb +4 -1
- data/lib/api_resource/response.rb +108 -0
- data/lib/api_resource/scopes.rb +62 -5
- data/lib/api_resource/serializer.rb +1 -1
- data/lib/api_resource/typecasters/boolean_typecaster.rb +1 -0
- data/lib/api_resource/typecasters/integer_typecaster.rb +1 -0
- data/lib/api_resource/typecasters/time_typecaster.rb +12 -4
- data/lib/api_resource/version.rb +1 -1
- data/lib/api_resource.rb +1 -0
- data/spec/lib/associations/has_one_remote_object_proxy_spec.rb +4 -4
- data/spec/lib/associations_spec.rb +3 -3
- data/spec/lib/attributes_spec.rb +16 -1
- data/spec/lib/base_spec.rb +121 -39
- data/spec/lib/conditions/{abstract_conditions_spec.rb → abstract_condition_spec.rb} +23 -11
- data/spec/lib/conditions/pagination_condition_spec.rb +88 -0
- data/spec/lib/finders/multi_object_association_finder_spec.rb +55 -27
- data/spec/lib/finders/resource_finder_spec.rb +26 -2
- data/spec/lib/finders/single_object_association_finder_spec.rb +14 -6
- data/spec/lib/finders_spec.rb +81 -81
- data/spec/lib/observing_spec.rb +3 -4
- data/spec/lib/response_spec.rb +18 -0
- data/spec/lib/scopes_spec.rb +25 -1
- data/spec/lib/typecasters/boolean_typecaster_spec.rb +1 -1
- data/spec/lib/typecasters/integer_typecaster_spec.rb +1 -1
- data/spec/lib/typecasters/time_typecaster_spec.rb +6 -0
- data/spec/support/files/bg-awesome.jpg +0 -0
- data/spec/support/mocks/test_resource_mocks.rb +26 -16
- data/spec/support/requests/test_resource_requests.rb +27 -23
- metadata +24 -4
@@ -1,110 +1,191 @@
|
|
1
1
|
|
2
2
|
module ApiResource
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
4
|
+
module Finders
|
5
|
+
|
6
|
+
class AbstractFinder
|
7
|
+
|
8
|
+
attr_accessor :condition, :klass
|
9
|
+
attr_reader :found, :internal_object
|
10
|
+
|
11
|
+
# TODO: Make this list longer since there are for sure more methods to delegate
|
12
|
+
delegate :to_s, :inspect, :reload, :present?, :blank?, :size, :count, :to => :internal_object
|
13
|
+
|
14
|
+
def initialize(klass, condition)
|
15
|
+
@klass = klass
|
16
|
+
@condition = condition
|
17
|
+
@found = false
|
18
|
+
|
19
|
+
@klass.load_resource_definition
|
20
|
+
end
|
21
|
+
|
22
|
+
#
|
23
|
+
# Allows us to respond correctly to instance_of? based
|
24
|
+
# on our internal_object
|
25
|
+
#
|
26
|
+
# @param klass [Class] Class to check
|
27
|
+
#
|
28
|
+
# @return [Boolean]
|
29
|
+
def instance_of?(klass)
|
30
|
+
super || self.internal_object.instance_of?(klass)
|
31
|
+
end
|
32
|
+
|
33
|
+
#
|
34
|
+
# Allows us to respond correctly to is_a? based
|
35
|
+
# on our internal_object
|
36
|
+
#
|
37
|
+
# @param klass [Class] Class to check
|
38
|
+
#
|
39
|
+
# @return [Boolean]
|
40
|
+
def is_a?(klass)
|
41
|
+
super || self.internal_object.is_a?(klass)
|
42
|
+
end
|
43
|
+
|
44
|
+
#
|
45
|
+
# Allows us to respond correctly to kind_of? based
|
46
|
+
# on our internal_object
|
47
|
+
#
|
48
|
+
# @param klass [Class] Class to check
|
49
|
+
#
|
50
|
+
# @return [Boolean]
|
51
|
+
def kind_of?(klass)
|
52
|
+
self.is_a?(klass)
|
53
|
+
end
|
54
|
+
|
55
|
+
#
|
56
|
+
# Return the headers for our response from
|
57
|
+
# the server
|
58
|
+
#
|
59
|
+
# @return [Hash] Headers hash
|
60
|
+
def headers
|
61
|
+
self.response.try(:headers)
|
62
|
+
end
|
63
|
+
|
64
|
+
def internal_object
|
65
|
+
# If we've already tried to load return what we've got
|
66
|
+
if instance_variable_defined?(:@internal_object)
|
67
|
+
return instance_variable_get(:@internal_object)
|
68
|
+
end
|
69
|
+
# If we haven't tried to load then just call load
|
70
|
+
self.load
|
71
|
+
end
|
72
|
+
|
73
|
+
def load
|
74
|
+
raise NotImplementedError("Must be defined in a subclass")
|
75
|
+
end
|
76
|
+
|
77
|
+
#
|
78
|
+
# Offset returned from the server
|
79
|
+
#
|
80
|
+
# @return [Fixnum]
|
81
|
+
def offset
|
82
|
+
self.headers.try(:[], 'ApiResource-Offset').to_i
|
83
|
+
end
|
84
|
+
|
85
|
+
#
|
86
|
+
# Is this a paginated find?
|
87
|
+
#
|
88
|
+
# @return [Boolean]
|
89
|
+
def paginated?
|
90
|
+
@condition.paginated?
|
91
|
+
end
|
92
|
+
|
93
|
+
#
|
94
|
+
# Total number of entries the server has told us are
|
95
|
+
# in our collection
|
96
|
+
#
|
97
|
+
# @return [Fixnum]
|
98
|
+
def total_entries
|
99
|
+
self.headers.try(:[], 'ApiResource-Total-Entries').to_i
|
100
|
+
end
|
101
|
+
|
102
|
+
#
|
103
|
+
# Getter for our response from the server
|
104
|
+
#
|
105
|
+
# @return [ApiResource::Response]
|
106
|
+
def response
|
107
|
+
@response ||= begin
|
108
|
+
self.klass.connection.get(self.build_load_path)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def all(*args)
|
113
|
+
if args.blank?
|
114
|
+
self.internal_object
|
115
|
+
else
|
116
|
+
self.klass.send(:all, *args)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
# proxy unknown methods to the internal_object
|
121
|
+
def method_missing(method, *args, &block)
|
122
|
+
self.internal_object.send(method, *args, &block)
|
123
|
+
end
|
124
|
+
|
125
|
+
protected
|
126
|
+
|
127
|
+
# This returns a hash of class_names (given by the condition object)
|
128
|
+
# to an array of objects
|
129
|
+
def load_includes(id_hash)
|
130
|
+
# Quit early if the condition is not eager
|
131
|
+
return {} unless self.condition.eager_load?
|
132
|
+
# Otherwise go through each class_name that is included, and load the ids
|
133
|
+
# given in id_hash, at this point we know all these associations have their
|
134
|
+
# proper names
|
135
|
+
|
136
|
+
hsh = HashWithIndifferentAccess.new
|
137
|
+
id_hash = HashWithIndifferentAccess.new(id_hash)
|
138
|
+
# load each individually
|
139
|
+
self.condition.included_objects.inject(hsh) do |accum, assoc|
|
140
|
+
id_hash[assoc].each_slice(400).each do |ids|
|
141
|
+
accum[assoc.to_sym] ||= []
|
142
|
+
accum[assoc.to_sym].concat(
|
143
|
+
self.klass.association_class(assoc).all(
|
144
|
+
:params => {:ids => ids}
|
145
|
+
)
|
146
|
+
)
|
147
|
+
end
|
148
|
+
accum
|
149
|
+
end
|
150
|
+
|
151
|
+
hsh
|
152
|
+
end
|
153
|
+
|
154
|
+
def apply_includes(objects, includes)
|
155
|
+
if !objects.is_a?(Enumerable)
|
156
|
+
objects = Array.wrap(objects)
|
157
|
+
end
|
158
|
+
|
159
|
+
objects.each do |obj|
|
160
|
+
includes.each_pair do |assoc, vals|
|
161
|
+
ids_to_keep = Array.wrap(obj.send(obj.class.association_foreign_key_field(assoc)))
|
162
|
+
to_keep = vals.select{|elm| ids_to_keep.include?(elm.id)}
|
163
|
+
# if this is a single association take the first
|
164
|
+
# TODO: subclass instead of this
|
165
|
+
if self.klass.has_many?(assoc)
|
166
|
+
obj.send("#{assoc}=", to_keep, false)
|
167
|
+
else
|
168
|
+
obj.send("#{assoc}=", to_keep.first, false)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def build_load_path
|
175
|
+
raise "This is not finding an association" unless self.condition.remote_path
|
95
176
|
|
96
177
|
path = self.condition.remote_path
|
97
178
|
# add a format if it doesn't exist and there is no query string yet
|
98
179
|
path += ".#{self.klass.format.extension}" unless path =~ /\./ || path =~/\?/
|
99
180
|
# add the query string, allowing for other user-provided options in the remote_path if we have options
|
100
181
|
unless self.condition.blank_conditions?
|
101
|
-
path += (path =~ /\?/ ? "&" : "?") + self.condition.to_query
|
182
|
+
path += (path =~ /\?/ ? "&" : "?") + self.condition.to_query
|
102
183
|
end
|
103
184
|
path
|
104
|
-
|
185
|
+
end
|
105
186
|
|
106
|
-
|
187
|
+
end
|
107
188
|
|
108
|
-
|
189
|
+
end
|
109
190
|
|
110
191
|
end
|
@@ -4,12 +4,17 @@ module ApiResource
|
|
4
4
|
|
5
5
|
class MultiObjectAssociationFinder < AbstractFinder
|
6
6
|
|
7
|
+
delegate :select,
|
8
|
+
to: :internal_object
|
9
|
+
|
7
10
|
# If they pass in the internal object just skip the first
|
8
11
|
# step and apply the includes
|
9
12
|
def initialize(klass, condition, internal_object = nil)
|
10
13
|
super(klass, condition)
|
11
14
|
|
12
|
-
|
15
|
+
if internal_object
|
16
|
+
@internal_object = internal_object
|
17
|
+
end
|
13
18
|
end
|
14
19
|
|
15
20
|
def load
|
@@ -18,15 +23,11 @@ module ApiResource
|
|
18
23
|
raise "Tried to load association without a remote path"
|
19
24
|
end
|
20
25
|
|
21
|
-
|
22
|
-
data = self.klass.connection.get(self.build_load_path)
|
23
|
-
return [] if data.blank?
|
26
|
+
return [] if self.response.blank?
|
24
27
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
@internal_object = self.klass.instantiate_collection(data)
|
29
|
-
end
|
28
|
+
@internal_object ||= self.klass.instantiate_collection(
|
29
|
+
Array.wrap(self.response)
|
30
|
+
)
|
30
31
|
|
31
32
|
@loaded = true
|
32
33
|
|
@@ -1,59 +1,69 @@
|
|
1
1
|
module ApiResource
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
3
|
+
module Finders
|
4
|
+
|
5
|
+
class ResourceFinder < AbstractFinder
|
6
|
+
|
7
|
+
# this is a little bit simpler, it's always a collection and does
|
8
|
+
# not require a remote path
|
9
|
+
def load
|
10
|
+
begin
|
11
|
+
return [] if self.response.blank?
|
12
|
+
|
13
|
+
@loaded = true
|
14
|
+
|
15
|
+
if self.response.is_a?(Array)
|
16
|
+
@internal_object = self.klass.instantiate_collection(
|
17
|
+
self.response
|
18
|
+
)
|
19
|
+
else
|
20
|
+
@internal_object = [
|
21
|
+
self.klass.instantiate_record(self.response)
|
22
|
+
]
|
23
|
+
end
|
24
|
+
|
25
|
+
id_hash = self.condition.included_objects.inject({}) do |accum, assoc|
|
26
|
+
accum[assoc] = @internal_object.collect do |obj|
|
27
|
+
obj.send(self.klass.association_foreign_key_field(assoc))
|
28
|
+
end
|
29
|
+
accum[assoc].flatten!
|
30
|
+
accum[assoc].uniq!
|
31
|
+
accum
|
32
|
+
end
|
33
|
+
included_objects = self.load_includes(id_hash)
|
34
|
+
|
35
|
+
self.apply_includes(@internal_object, included_objects)
|
36
|
+
|
37
|
+
|
38
|
+
# Removed to mirror ActiveRecord
|
39
|
+
# e.g. LifebookerClient::Provider.find([1])
|
40
|
+
#
|
41
|
+
# # looks hacky, but we want to return only a single
|
42
|
+
# # object in case of a find call.
|
43
|
+
# if @internal_object.count == 1 && self.build_load_path =~ /(&|\?)find/
|
44
|
+
# @internal_object = @internal_object.first
|
45
|
+
# end
|
46
|
+
|
47
|
+
return @internal_object
|
48
|
+
rescue ApiResource::ResourceNotFound
|
49
|
+
nil
|
50
|
+
end
|
51
|
+
@internal_object
|
52
|
+
end
|
53
|
+
|
54
|
+
protected
|
47
55
|
|
48
56
|
|
49
57
|
# Find every resource
|
50
58
|
def build_load_path
|
51
|
-
|
52
|
-
|
59
|
+
prefix_opts, query_opts = self.klass.split_options(
|
60
|
+
self.condition.to_hash
|
61
|
+
)
|
62
|
+
self.klass.collection_path(prefix_opts, query_opts)
|
53
63
|
end
|
54
64
|
|
55
|
-
|
65
|
+
end
|
56
66
|
|
57
|
-
|
67
|
+
end
|
58
68
|
|
59
|
-
end
|
69
|
+
end
|
@@ -5,20 +5,19 @@ module ApiResource
|
|
5
5
|
class SingleFinder < AbstractFinder
|
6
6
|
|
7
7
|
def load
|
8
|
-
|
8
|
+
return nil if self.response.blank?
|
9
9
|
|
10
10
|
@loaded = true
|
11
|
-
return nil if data.blank?
|
12
11
|
|
13
|
-
@internal_object = self.klass.instantiate_record(
|
12
|
+
@internal_object = self.klass.instantiate_record(self.response)
|
14
13
|
# now that the object is loaded, resolve the includes
|
15
|
-
id_hash = self.condition.included_objects.inject({}) do |
|
16
|
-
|
14
|
+
id_hash = self.condition.included_objects.inject({}) do |hash, assoc|
|
15
|
+
hash[assoc] = Array.wrap(
|
17
16
|
@internal_object.send(
|
18
17
|
@internal_object.class.association_foreign_key_field(assoc)
|
19
18
|
)
|
20
19
|
)
|
21
|
-
|
20
|
+
hash
|
22
21
|
end
|
23
22
|
|
24
23
|
included_objects = self.load_includes(id_hash)
|
@@ -1,55 +1,56 @@
|
|
1
1
|
module ApiResource
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
3
|
+
module Finders
|
4
|
+
|
5
|
+
class SingleObjectAssociationFinder < AbstractFinder
|
6
|
+
|
7
|
+
def initialize(klass, condition, internal_object = nil)
|
8
|
+
super(klass, condition)
|
9
|
+
@internal_object = internal_object
|
10
|
+
end
|
11
|
+
|
12
|
+
# since it is only a single object we can just load from
|
13
|
+
# the service_uri and deal with includes
|
14
|
+
def load
|
15
|
+
# otherwise just instantiate the record
|
16
|
+
unless self.condition.remote_path
|
17
|
+
raise "Tried to load association without a remote path"
|
18
|
+
end
|
19
|
+
|
20
|
+
# check our response
|
21
|
+
return nil if self.response.blank?
|
22
|
+
|
23
|
+
# get our internal object
|
24
|
+
@internal_object ||= begin
|
25
|
+
if self.response.is_a?(Array)
|
26
|
+
self.klass.instantiate_record(self.response.first)
|
27
|
+
else
|
28
|
+
self.klass.instantiate_record(self.response)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# mark us as loaded
|
33
|
+
@loaded = true
|
34
|
+
|
35
|
+
# now that the object is loaded, resolve the includes
|
36
|
+
id_hash = self.condition.included_objects.inject({}) do |hash, assoc|
|
37
|
+
hash[assoc] = Array.wrap(
|
38
|
+
@internal_object.send(
|
39
|
+
@internal_object.class.association_foreign_key_field(assoc)
|
40
|
+
)
|
41
|
+
)
|
42
|
+
hash
|
43
|
+
end
|
44
|
+
|
45
|
+
# apply our includes
|
46
|
+
included_objects = self.load_includes(id_hash)
|
47
|
+
self.apply_includes(@internal_object, included_objects)
|
48
|
+
|
49
|
+
return @internal_object
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
54
55
|
|
55
56
|
end
|
data/lib/api_resource/finders.rb
CHANGED
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'active_support/json'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module ApiResource
|
5
|
+
module Formats
|
6
|
+
|
7
|
+
|
8
|
+
#
|
9
|
+
# @module FileUploadFormat
|
10
|
+
#
|
11
|
+
# Class to handle posting of multipart data to HTTPClient
|
12
|
+
#
|
13
|
+
module FileUploadFormat
|
14
|
+
extend self
|
15
|
+
|
16
|
+
#
|
17
|
+
# The extension for the request
|
18
|
+
#
|
19
|
+
# @return [String]
|
20
|
+
#
|
21
|
+
def extension
|
22
|
+
"json"
|
23
|
+
end
|
24
|
+
|
25
|
+
#
|
26
|
+
# The mime_type header for the request
|
27
|
+
#
|
28
|
+
# @return [String]
|
29
|
+
#
|
30
|
+
def mime_type
|
31
|
+
"multipart/form-data"
|
32
|
+
end
|
33
|
+
|
34
|
+
#
|
35
|
+
# Implementation of {#encode} - encodes data to POST
|
36
|
+
# to the server
|
37
|
+
#
|
38
|
+
# @return [Hash]
|
39
|
+
#
|
40
|
+
def encode(hash, options = nil)
|
41
|
+
ret = {}
|
42
|
+
hash.each_pair do |k,v|
|
43
|
+
ret[k] = self.encode_value(v)
|
44
|
+
end
|
45
|
+
ret
|
46
|
+
end
|
47
|
+
|
48
|
+
#
|
49
|
+
# Implementation of {#decode} - decodes data back from the server
|
50
|
+
# We expect the data to be JSON-formatted
|
51
|
+
#
|
52
|
+
# @return [Hash]
|
53
|
+
#
|
54
|
+
def decode(json)
|
55
|
+
JSON.parse(json)
|
56
|
+
end
|
57
|
+
|
58
|
+
protected
|
59
|
+
|
60
|
+
def encode_value(val)
|
61
|
+
case val
|
62
|
+
when Hash
|
63
|
+
self.encode(val)
|
64
|
+
when Array
|
65
|
+
val.collect{|v| self.encode_value(v)}
|
66
|
+
when ActionDispatch::Http::UploadedFile
|
67
|
+
val.tempfile
|
68
|
+
else
|
69
|
+
val
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
data/lib/api_resource/formats.rb
CHANGED
@@ -1,7 +1,10 @@
|
|
1
1
|
module ApiResource
|
2
2
|
module Formats
|
3
|
-
|
3
|
+
|
4
|
+
autoload :FileUploadFormat, 'api_resource/formats/file_upload_format'
|
4
5
|
autoload :JsonFormat, 'api_resource/formats/json_format'
|
6
|
+
autoload :XmlFormat, 'api_resource/formats/xml_format'
|
7
|
+
|
5
8
|
|
6
9
|
# Lookup the format class from a mime type reference symbol. Example:
|
7
10
|
#
|