jsonapi-resources 0.0.7 → 0.0.8
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/README.md +4 -5
- data/lib/jsonapi-resources.rb +2 -1
- data/lib/jsonapi/association.rb +19 -8
- data/lib/jsonapi/formatter.rb +2 -0
- data/lib/jsonapi/request.rb +9 -9
- data/lib/jsonapi/resource.rb +52 -28
- data/lib/jsonapi/resource_controller.rb +10 -2
- data/lib/jsonapi/resource_for.rb +2 -0
- data/lib/jsonapi/resource_serializer.rb +11 -10
- data/lib/jsonapi/resources/version.rb +1 -1
- data/lib/jsonapi/routing_ext.rb +5 -0
- data/test/controllers/controller_test.rb +2 -2
- data/test/fixtures/active_record.rb +6 -5
- data/test/helpers/hash_helpers.rb +3 -1
- data/test/integration/routes/routes_test.rb +6 -0
- data/test/unit/serializer/serializer_test.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3e063aecb3183d3a1862dc4fd88f0f06ddc921dd
|
|
4
|
+
data.tar.gz: 40b0476410fe269a08f16791f8b927d2aee02156
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f4135619c0ad660679b93ea9dcde314991134824e0d01540705b4a3055e0acccfab76d74b0e49cf94d969d949063a51c50328165265b90b2057065ec34b13eb3
|
|
7
|
+
data.tar.gz: 335f3f2b30251c07b2286dbdcd176d3f199fd844d99f6c9619a0b54e598b66e0fe07b1386cddb1c18106b3e1d968e6a6a1f5eaabb11e3cc72d75d08bf54581ae
|
data/README.md
CHANGED
|
@@ -145,13 +145,13 @@ end
|
|
|
145
145
|
|
|
146
146
|
The system will lookup a value formatter named `DateWithTimezoneValueFormatter` and will use this when serializing and updating the attribute. See the [Value Formatters](#value-formatters) section for more details.
|
|
147
147
|
|
|
148
|
-
#### Key
|
|
148
|
+
#### Primary Key
|
|
149
149
|
|
|
150
|
-
|
|
150
|
+
Resources are always represented using a key of `id`. If the underlying model does not use `id` as the primary key you can use the `primary_key` method to tell the resource which field on the model to use as the primary key. Note: this doesn't have to be the actual primary key of the model. For example you may wish to use integers internally and a different scheme publicly.
|
|
151
151
|
|
|
152
152
|
```ruby
|
|
153
153
|
class CurrencyResource < JSONAPI::Resource
|
|
154
|
-
|
|
154
|
+
primary_key :code
|
|
155
155
|
attributes :code, :name
|
|
156
156
|
|
|
157
157
|
has_many :expense_entries
|
|
@@ -199,8 +199,7 @@ end
|
|
|
199
199
|
|
|
200
200
|
The association methods support the following options:
|
|
201
201
|
* `class_name` - a string specifying the underlying class for the related resource
|
|
202
|
-
* `
|
|
203
|
-
* `key` - the key in the resource that identifies the related resource, if different than `<resource_name>_id`
|
|
202
|
+
* `foreign_key` - the method on the resource used to fetch the related resource. Defaults to `<resource_name>_id` for has_one and `<resource_name>_ids` for has_many relationships.
|
|
204
203
|
* `acts_as_set` - allows the entire set of related records to be replaced in one operation. Defaults to false if not set.
|
|
205
204
|
|
|
206
205
|
Examples:
|
data/lib/jsonapi-resources.rb
CHANGED
data/lib/jsonapi/association.rb
CHANGED
|
@@ -1,13 +1,24 @@
|
|
|
1
1
|
module JSONAPI
|
|
2
2
|
class Association
|
|
3
|
-
attr_reader :
|
|
3
|
+
attr_reader :acts_as_set, :foreign_key, :type, :options, :name, :class_name
|
|
4
4
|
|
|
5
5
|
def initialize(name, options={})
|
|
6
|
-
@name
|
|
7
|
-
@options
|
|
8
|
-
@
|
|
9
|
-
@
|
|
10
|
-
|
|
6
|
+
@name = name.to_s
|
|
7
|
+
@options = options
|
|
8
|
+
@acts_as_set = options.fetch(:acts_as_set, false) == true
|
|
9
|
+
@key = options[:key] ? options[:key].to_sym : nil
|
|
10
|
+
|
|
11
|
+
if @key.nil?
|
|
12
|
+
@foreign_key = options[:foreign_key ] ? options[:foreign_key ].to_sym : nil
|
|
13
|
+
else
|
|
14
|
+
# :nocov:
|
|
15
|
+
warn '[DEPRECATION] `key` is deprecated in associations. Please use `foreign_key` instead.'
|
|
16
|
+
# :nocov:
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def primary_key
|
|
21
|
+
@primary_key ||= Resource.resource_for(@name)._primary_key
|
|
11
22
|
end
|
|
12
23
|
|
|
13
24
|
class HasOne < Association
|
|
@@ -15,7 +26,7 @@ module JSONAPI
|
|
|
15
26
|
super
|
|
16
27
|
@class_name = options.fetch(:class_name, name.to_s.capitalize)
|
|
17
28
|
@type = class_name.underscore.pluralize.to_sym
|
|
18
|
-
@
|
|
29
|
+
@foreign_key ||= @key.nil? ? "#{name}_id".to_sym : @key
|
|
19
30
|
end
|
|
20
31
|
end
|
|
21
32
|
|
|
@@ -24,7 +35,7 @@ module JSONAPI
|
|
|
24
35
|
super
|
|
25
36
|
@class_name = options.fetch(:class_name, name.to_s.capitalize.singularize)
|
|
26
37
|
@type = class_name.underscore.pluralize.to_sym
|
|
27
|
-
@key
|
|
38
|
+
@foreign_key ||= @key.nil? ? "#{name.to_s.singularize}_ids".to_sym : @key
|
|
28
39
|
end
|
|
29
40
|
end
|
|
30
41
|
end
|
data/lib/jsonapi/formatter.rb
CHANGED
|
@@ -9,6 +9,7 @@ module JSONAPI
|
|
|
9
9
|
arg
|
|
10
10
|
end
|
|
11
11
|
|
|
12
|
+
# :nocov:
|
|
12
13
|
if RUBY_VERSION >= '2.0'
|
|
13
14
|
def formatter_for(format)
|
|
14
15
|
formatter_class_name = "#{format.to_s.camelize}Formatter"
|
|
@@ -20,6 +21,7 @@ module JSONAPI
|
|
|
20
21
|
formatter_class_name.safe_constantize if formatter_class_name
|
|
21
22
|
end
|
|
22
23
|
end
|
|
24
|
+
# :nocov:
|
|
23
25
|
end
|
|
24
26
|
end
|
|
25
27
|
|
data/lib/jsonapi/request.rb
CHANGED
|
@@ -298,31 +298,31 @@ module JSONAPI
|
|
|
298
298
|
def parse_replace_operation(params)
|
|
299
299
|
object_params_raw = params.require(format_key(@resource_klass._type))
|
|
300
300
|
|
|
301
|
-
keys = params[@resource_klass.
|
|
301
|
+
keys = params[@resource_klass._primary_key]
|
|
302
302
|
if object_params_raw.is_a?(Array)
|
|
303
303
|
if keys.count != object_params_raw.count
|
|
304
304
|
raise JSONAPI::Exceptions::CountMismatch
|
|
305
305
|
end
|
|
306
306
|
|
|
307
307
|
object_params_raw.each do |object_params|
|
|
308
|
-
if object_params[@resource_klass.
|
|
308
|
+
if object_params[@resource_klass._primary_key].nil?
|
|
309
309
|
raise JSONAPI::Exceptions::MissingKey.new
|
|
310
310
|
end
|
|
311
311
|
|
|
312
|
-
if !keys.include?(object_params[@resource_klass.
|
|
313
|
-
raise JSONAPI::Exceptions::KeyNotIncludedInURL.new(object_params[@resource_klass.
|
|
312
|
+
if !keys.include?(object_params[@resource_klass._primary_key])
|
|
313
|
+
raise JSONAPI::Exceptions::KeyNotIncludedInURL.new(object_params[@resource_klass._primary_key])
|
|
314
314
|
end
|
|
315
315
|
@operations.push JSONAPI::ReplaceFieldsOperation.new(@resource_klass,
|
|
316
|
-
object_params[@resource_klass.
|
|
316
|
+
object_params[@resource_klass._primary_key],
|
|
317
317
|
parse_params(object_params, @resource_klass.updateable_fields(@context)))
|
|
318
318
|
end
|
|
319
319
|
else
|
|
320
|
-
if !object_params_raw[@resource_klass.
|
|
321
|
-
raise JSONAPI::Exceptions::KeyNotIncludedInURL.new(object_params_raw[@resource_klass.
|
|
320
|
+
if !object_params_raw[@resource_klass._primary_key].nil? && keys != object_params_raw[@resource_klass._primary_key]
|
|
321
|
+
raise JSONAPI::Exceptions::KeyNotIncludedInURL.new(object_params_raw[@resource_klass._primary_key])
|
|
322
322
|
end
|
|
323
323
|
|
|
324
324
|
@operations.push JSONAPI::ReplaceFieldsOperation.new(@resource_klass,
|
|
325
|
-
params[@resource_klass.
|
|
325
|
+
params[@resource_klass._primary_key],
|
|
326
326
|
parse_params(object_params_raw, @resource_klass.updateable_fields(@context)))
|
|
327
327
|
end
|
|
328
328
|
|
|
@@ -333,7 +333,7 @@ module JSONAPI
|
|
|
333
333
|
end
|
|
334
334
|
|
|
335
335
|
def parse_remove_operation(params)
|
|
336
|
-
keys = parse_key_array(params.permit(@resource_klass.
|
|
336
|
+
keys = parse_key_array(params.permit(@resource_klass._primary_key)[@resource_klass._primary_key])
|
|
337
337
|
|
|
338
338
|
keys.each do |key|
|
|
339
339
|
@operations.push JSONAPI::RemoveResourceOperation.new(@resource_klass, key)
|
data/lib/jsonapi/resource.rb
CHANGED
|
@@ -20,6 +20,10 @@ module JSONAPI
|
|
|
20
20
|
@model.destroy
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
+
def id
|
|
24
|
+
model.send(self.class._primary_key)
|
|
25
|
+
end
|
|
26
|
+
|
|
23
27
|
def create_has_many_link(association_type, association_key_value)
|
|
24
28
|
association = self.class._associations[association_type]
|
|
25
29
|
related_resource = self.class.resource_for(association.type).find_by_key(association_key_value, @context)
|
|
@@ -36,16 +40,16 @@ module JSONAPI
|
|
|
36
40
|
def replace_has_many_links(association_type, association_key_values)
|
|
37
41
|
association = self.class._associations[association_type]
|
|
38
42
|
|
|
39
|
-
|
|
43
|
+
send("#{association.foreign_key}=", association_key_values)
|
|
40
44
|
end
|
|
41
45
|
|
|
42
46
|
def create_has_one_link(association_type, association_key_value)
|
|
43
47
|
association = self.class._associations[association_type]
|
|
44
48
|
|
|
45
49
|
# ToDo: Add option to skip relations that already exist instead of returning an error?
|
|
46
|
-
relation = @model.send("#{association.
|
|
50
|
+
relation = @model.send("#{association.foreign_key}")
|
|
47
51
|
if relation.nil?
|
|
48
|
-
|
|
52
|
+
send("#{association.foreign_key}=", association_key_value)
|
|
49
53
|
else
|
|
50
54
|
raise JSONAPI::Exceptions::HasOneRelationExists.new
|
|
51
55
|
end
|
|
@@ -54,7 +58,7 @@ module JSONAPI
|
|
|
54
58
|
def replace_has_one_link(association_type, association_key_value)
|
|
55
59
|
association = self.class._associations[association_type]
|
|
56
60
|
|
|
57
|
-
|
|
61
|
+
send("#{association.foreign_key}=", association_key_value)
|
|
58
62
|
end
|
|
59
63
|
|
|
60
64
|
def remove_has_many_link(association_type, key)
|
|
@@ -66,12 +70,18 @@ module JSONAPI
|
|
|
66
70
|
def remove_has_one_link(association_type)
|
|
67
71
|
association = self.class._associations[association_type]
|
|
68
72
|
|
|
69
|
-
|
|
73
|
+
send("#{association.foreign_key}=", nil)
|
|
70
74
|
end
|
|
71
75
|
|
|
72
76
|
def replace_fields(field_data)
|
|
73
77
|
field_data[:attributes].each do |attribute, value|
|
|
74
|
-
|
|
78
|
+
begin
|
|
79
|
+
send "#{attribute}=", value
|
|
80
|
+
rescue ArgumentError
|
|
81
|
+
# :nocov: Will be thrown if an enum value isn't allowed for an enum. Currently not tested as enums are a rails 4.1 and higher feature
|
|
82
|
+
raise JSONAPI::Exceptions::InvalidFieldValue.new(attribute, value)
|
|
83
|
+
# :nocov:
|
|
84
|
+
end
|
|
75
85
|
end
|
|
76
86
|
|
|
77
87
|
field_data[:has_one].each do |association_type, value|
|
|
@@ -184,7 +194,14 @@ module JSONAPI
|
|
|
184
194
|
end
|
|
185
195
|
|
|
186
196
|
def key(key)
|
|
187
|
-
|
|
197
|
+
# :nocov:
|
|
198
|
+
warn '[DEPRECATION] `key` is deprecated. Please use `primary_key` instead.'
|
|
199
|
+
@_primary_key = key.to_sym
|
|
200
|
+
# :nocov:
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
def primary_key(key)
|
|
204
|
+
@_primary_key = key.to_sym
|
|
188
205
|
end
|
|
189
206
|
|
|
190
207
|
# Override in your resource to filter the updateable keys
|
|
@@ -212,7 +229,7 @@ module JSONAPI
|
|
|
212
229
|
includes.push(filter)
|
|
213
230
|
where_filters["#{filter}.#{_associations[filter].primary_key}"] = value
|
|
214
231
|
else
|
|
215
|
-
where_filters["#{_associations[filter].
|
|
232
|
+
where_filters["#{_associations[filter].foreign_key}"] = value
|
|
216
233
|
end
|
|
217
234
|
else
|
|
218
235
|
where_filters[filter] = value
|
|
@@ -228,7 +245,7 @@ module JSONAPI
|
|
|
228
245
|
end
|
|
229
246
|
|
|
230
247
|
def find_by_key(key, context = nil)
|
|
231
|
-
model = _model_class.where({
|
|
248
|
+
model = _model_class.where({_primary_key => key}).first
|
|
232
249
|
if model.nil?
|
|
233
250
|
raise JSONAPI::Exceptions::RecordNotFound.new(key)
|
|
234
251
|
end
|
|
@@ -305,15 +322,22 @@ module JSONAPI
|
|
|
305
322
|
end
|
|
306
323
|
|
|
307
324
|
def _key
|
|
308
|
-
|
|
325
|
+
# :nocov:
|
|
326
|
+
warn '[DEPRECATION] `_key` is deprecated. Please use `_primary_key` instead.'
|
|
327
|
+
_primary_key
|
|
328
|
+
# :nocov:
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
def _primary_key
|
|
332
|
+
@_primary_key ||= :id
|
|
309
333
|
end
|
|
310
334
|
|
|
311
335
|
def _as_parent_key
|
|
312
|
-
@_as_parent_key ||= "#{_type.to_s.singularize}_#{
|
|
336
|
+
@_as_parent_key ||= "#{_type.to_s.singularize}_#{_primary_key}"
|
|
313
337
|
end
|
|
314
338
|
|
|
315
339
|
def _allowed_filters
|
|
316
|
-
!@_allowed_filters.nil? ? @_allowed_filters : Set.new([
|
|
340
|
+
!@_allowed_filters.nil? ? @_allowed_filters : Set.new([_primary_key])
|
|
317
341
|
end
|
|
318
342
|
|
|
319
343
|
def _resource_name_from_type(type)
|
|
@@ -325,15 +349,17 @@ module JSONAPI
|
|
|
325
349
|
return class_name
|
|
326
350
|
end
|
|
327
351
|
|
|
352
|
+
# :nocov:
|
|
328
353
|
if RUBY_VERSION >= '2.0'
|
|
329
354
|
def _model_class
|
|
330
|
-
@model ||= Object.const_get(_model_name)
|
|
355
|
+
@model ||= Object.const_get(_model_name.to_s)
|
|
331
356
|
end
|
|
332
357
|
else
|
|
333
358
|
def _model_class
|
|
334
359
|
@model ||= _model_name.to_s.safe_constantize
|
|
335
360
|
end
|
|
336
361
|
end
|
|
362
|
+
# :nocov:
|
|
337
363
|
|
|
338
364
|
def _allowed_filter?(filter)
|
|
339
365
|
_allowed_filters.include?(filter)
|
|
@@ -347,29 +373,27 @@ module JSONAPI
|
|
|
347
373
|
attrs.each do |attr|
|
|
348
374
|
@_associations[attr] = klass.new(attr, options)
|
|
349
375
|
|
|
350
|
-
|
|
351
|
-
|
|
376
|
+
foreign_key = @_associations[attr].foreign_key
|
|
377
|
+
|
|
378
|
+
define_method foreign_key do
|
|
379
|
+
@model.method(foreign_key).call
|
|
380
|
+
end unless method_defined?(foreign_key)
|
|
352
381
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
382
|
+
define_method "#{foreign_key}=" do |value|
|
|
383
|
+
@model.method("#{foreign_key}=").call(value)
|
|
384
|
+
end unless method_defined?("#{foreign_key}=")
|
|
356
385
|
|
|
357
|
-
|
|
386
|
+
if @_associations[attr].is_a?(JSONAPI::Association::HasOne)
|
|
387
|
+
define_method attr do
|
|
358
388
|
type_name = self.class._associations[attr].type
|
|
359
389
|
resource_class = self.class.resource_for(type_name)
|
|
360
390
|
if resource_class
|
|
361
391
|
associated_model = @model.send attr
|
|
362
392
|
return resource_class.new(associated_model, @context)
|
|
363
393
|
end
|
|
364
|
-
end unless method_defined?(
|
|
394
|
+
end unless method_defined?(attr)
|
|
365
395
|
elsif @_associations[attr].is_a?(JSONAPI::Association::HasMany)
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
define_method key do
|
|
369
|
-
@model.method(key).call
|
|
370
|
-
end unless method_defined?(key)
|
|
371
|
-
|
|
372
|
-
define_method "_#{attr}_resources" do
|
|
396
|
+
define_method attr do
|
|
373
397
|
type_name = self.class._associations[attr].type
|
|
374
398
|
resource_class = self.class.resource_for(type_name)
|
|
375
399
|
resources = []
|
|
@@ -380,7 +404,7 @@ module JSONAPI
|
|
|
380
404
|
end
|
|
381
405
|
end
|
|
382
406
|
return resources
|
|
383
|
-
end unless method_defined?(
|
|
407
|
+
end unless method_defined?(attr)
|
|
384
408
|
end
|
|
385
409
|
end
|
|
386
410
|
end
|
|
@@ -27,7 +27,7 @@ module JSONAPI
|
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
def show
|
|
30
|
-
keys = parse_key_array(params[resource_klass.
|
|
30
|
+
keys = parse_key_array(params[resource_klass._primary_key])
|
|
31
31
|
|
|
32
32
|
if keys.length > 1
|
|
33
33
|
resources = []
|
|
@@ -56,9 +56,11 @@ module JSONAPI
|
|
|
56
56
|
parent_resource = resource_klass.find_by_key(parent_key, context)
|
|
57
57
|
|
|
58
58
|
association = resource_klass._association(association_type)
|
|
59
|
-
render json: { association_type => parent_resource.send(association.
|
|
59
|
+
render json: { association_type => parent_resource.send(association.foreign_key)}
|
|
60
60
|
rescue => e
|
|
61
|
+
# :nocov:
|
|
61
62
|
handle_exceptions(e)
|
|
63
|
+
# :nocov:
|
|
62
64
|
end
|
|
63
65
|
|
|
64
66
|
def create
|
|
@@ -91,6 +93,7 @@ module JSONAPI
|
|
|
91
93
|
end
|
|
92
94
|
|
|
93
95
|
private
|
|
96
|
+
# :nocov:
|
|
94
97
|
if RUBY_VERSION >= '2.0'
|
|
95
98
|
def resource_klass
|
|
96
99
|
@resource_klass ||= Object.const_get resource_klass_name
|
|
@@ -100,6 +103,7 @@ module JSONAPI
|
|
|
100
103
|
@resource_klass ||= resource_klass_name.safe_constantize
|
|
101
104
|
end
|
|
102
105
|
end
|
|
106
|
+
# :nocov:
|
|
103
107
|
|
|
104
108
|
def resource_klass_name
|
|
105
109
|
@resource_klass_name ||= "#{self.class.name.demodulize.sub(/Controller$/, '').singularize}Resource"
|
|
@@ -112,7 +116,9 @@ module JSONAPI
|
|
|
112
116
|
})
|
|
113
117
|
render_errors(@request.errors) unless @request.errors.empty?
|
|
114
118
|
rescue => e
|
|
119
|
+
# :nocov:
|
|
115
120
|
handle_exceptions(e)
|
|
121
|
+
# :nocov:
|
|
116
122
|
end
|
|
117
123
|
|
|
118
124
|
def parse_key_array(raw)
|
|
@@ -187,7 +193,9 @@ module JSONAPI
|
|
|
187
193
|
when JSONAPI::Exceptions::Error
|
|
188
194
|
render_errors(e.errors)
|
|
189
195
|
else # raise all other exceptions
|
|
196
|
+
# :nocov:
|
|
190
197
|
raise e
|
|
198
|
+
# :nocov:
|
|
191
199
|
end
|
|
192
200
|
end
|
|
193
201
|
end
|
data/lib/jsonapi/resource_for.rb
CHANGED
|
@@ -5,6 +5,7 @@ module JSONAPI
|
|
|
5
5
|
end
|
|
6
6
|
|
|
7
7
|
module ClassMethods
|
|
8
|
+
# :nocov:
|
|
8
9
|
if RUBY_VERSION >= '2.0'
|
|
9
10
|
def resource_for(type)
|
|
10
11
|
resource_name = JSONAPI::Resource._resource_name_from_type(type)
|
|
@@ -18,6 +19,7 @@ module JSONAPI
|
|
|
18
19
|
resource_name.safe_constantize if resource_name
|
|
19
20
|
end
|
|
20
21
|
end
|
|
22
|
+
# :nocov:
|
|
21
23
|
end
|
|
22
24
|
end
|
|
23
25
|
end
|
|
@@ -91,16 +91,17 @@ module JSONAPI
|
|
|
91
91
|
# The fields options controls both fields and included links references.
|
|
92
92
|
def process_primary(source, requested_associations)
|
|
93
93
|
if source.respond_to?(:to_ary)
|
|
94
|
-
source.each do |
|
|
95
|
-
id =
|
|
94
|
+
source.each do |resource|
|
|
95
|
+
id = resource.id
|
|
96
96
|
if already_serialized?(@primary_class_name, id)
|
|
97
97
|
set_primary(@primary_class_name, id)
|
|
98
98
|
end
|
|
99
99
|
|
|
100
|
-
add_linked_object(@primary_class_name, id, object_hash(
|
|
100
|
+
add_linked_object(@primary_class_name, id, object_hash(resource, requested_associations), true)
|
|
101
101
|
end
|
|
102
102
|
else
|
|
103
|
-
|
|
103
|
+
resource = source
|
|
104
|
+
id = resource.id
|
|
104
105
|
# ToDo: See if this is actually needed
|
|
105
106
|
# if already_serialized?(@primary_class_name, id)
|
|
106
107
|
# set_primary(@primary_class_name, id)
|
|
@@ -151,10 +152,10 @@ module JSONAPI
|
|
|
151
152
|
included_associations = source.fetchable_fields & associations.keys
|
|
152
153
|
associations.each_with_object({}) do |(name, association), hash|
|
|
153
154
|
if included_associations.include? name
|
|
154
|
-
|
|
155
|
+
foreign_key = association.foreign_key
|
|
155
156
|
|
|
156
157
|
if field_set.include?(name)
|
|
157
|
-
hash[format_key(name)] = source.send(
|
|
158
|
+
hash[format_key(name)] = source.send(foreign_key)
|
|
158
159
|
end
|
|
159
160
|
|
|
160
161
|
ia = requested_associations.is_a?(Hash) ? requested_associations[name] : nil
|
|
@@ -169,9 +170,9 @@ module JSONAPI
|
|
|
169
170
|
# through the associations.
|
|
170
171
|
if include_linked_object || include_linked_children
|
|
171
172
|
if association.is_a?(JSONAPI::Association::HasOne)
|
|
172
|
-
resource = source.send(
|
|
173
|
+
resource = source.send(name)
|
|
173
174
|
if resource
|
|
174
|
-
id = resource.
|
|
175
|
+
id = resource.id
|
|
175
176
|
associations_only = already_serialized?(type, id)
|
|
176
177
|
if include_linked_object && !associations_only
|
|
177
178
|
add_linked_object(type, id, object_hash(resource, ia[:include_related]))
|
|
@@ -180,9 +181,9 @@ module JSONAPI
|
|
|
180
181
|
end
|
|
181
182
|
end
|
|
182
183
|
elsif association.is_a?(JSONAPI::Association::HasMany)
|
|
183
|
-
resources = source.send(
|
|
184
|
+
resources = source.send(name)
|
|
184
185
|
resources.each do |resource|
|
|
185
|
-
id = resource.
|
|
186
|
+
id = resource.id
|
|
186
187
|
associations_only = already_serialized?(type, id)
|
|
187
188
|
if include_linked_object && !associations_only
|
|
188
189
|
add_linked_object(type, id, object_hash(resource, ia[:include_related]))
|
data/lib/jsonapi/routing_ext.rb
CHANGED
|
@@ -7,6 +7,7 @@ module ActionDispatch
|
|
|
7
7
|
options = resources.extract_options!.dup
|
|
8
8
|
|
|
9
9
|
res = JSONAPI::Resource.resource_for(resource_type)
|
|
10
|
+
|
|
10
11
|
resource resource_type, options.merge(res.routing_resource_options) do
|
|
11
12
|
@scope[:jsonapi_resource] = resource_type
|
|
12
13
|
|
|
@@ -29,6 +30,10 @@ module ActionDispatch
|
|
|
29
30
|
options = resources.extract_options!.dup
|
|
30
31
|
|
|
31
32
|
res = JSONAPI::Resource.resource_for(resource_type)
|
|
33
|
+
|
|
34
|
+
# Route using the primary_key. Can be overridden using routing_resource_options
|
|
35
|
+
options.merge!(param: res._primary_key)
|
|
36
|
+
|
|
32
37
|
resources resource_type, options.merge(res.routing_resource_options) do
|
|
33
38
|
@scope[:jsonapi_resource] = resource_type
|
|
34
39
|
|
|
@@ -1001,7 +1001,7 @@ class ExpenseEntriesControllerTest < ActionController::TestCase
|
|
|
1001
1001
|
|
|
1002
1002
|
def test_expense_entries_show_fields_type_many
|
|
1003
1003
|
get :show, {id: 1, include: 'isoCurrency,employee', 'fields' => {'expenseEntries' => 'transactionDate',
|
|
1004
|
-
'isoCurrencies' => '
|
|
1004
|
+
'isoCurrencies' => 'id,name'}}
|
|
1005
1005
|
assert_response :success
|
|
1006
1006
|
assert json_response['expenseEntries'].is_a?(Hash)
|
|
1007
1007
|
assert json_response['expenseEntries'].has_key?('transactionDate')
|
|
@@ -1009,7 +1009,7 @@ class ExpenseEntriesControllerTest < ActionController::TestCase
|
|
|
1009
1009
|
refute json_response['expenseEntries'].has_key?('links')
|
|
1010
1010
|
assert_equal 1, json_response['linked']['isoCurrencies'].size
|
|
1011
1011
|
assert_equal 1, json_response['linked']['people'].size
|
|
1012
|
-
assert json_response['linked']['isoCurrencies'][0].has_key?('
|
|
1012
|
+
assert json_response['linked']['isoCurrencies'][0].has_key?('id')
|
|
1013
1013
|
assert json_response['linked']['isoCurrencies'][0].has_key?('name')
|
|
1014
1014
|
refute json_response['linked']['isoCurrencies'][0].has_key?('countryName')
|
|
1015
1015
|
end
|
|
@@ -398,17 +398,15 @@ class PostResource < JSONAPI::Resource
|
|
|
398
398
|
end
|
|
399
399
|
|
|
400
400
|
class IsoCurrencyResource < JSONAPI::Resource
|
|
401
|
-
|
|
402
|
-
attributes :
|
|
403
|
-
|
|
404
|
-
routing_options :param => :code
|
|
401
|
+
primary_key :code
|
|
402
|
+
attributes :id, :name, :country_name, :minor_unit
|
|
405
403
|
end
|
|
406
404
|
|
|
407
405
|
class ExpenseEntryResource < JSONAPI::Resource
|
|
408
406
|
attributes :id, :cost
|
|
409
407
|
attribute :transaction_date, format: :date
|
|
410
408
|
|
|
411
|
-
has_one :iso_currency,
|
|
409
|
+
has_one :iso_currency, foreign_key: 'currency_code'
|
|
412
410
|
has_one :employee, class_name: 'Person'
|
|
413
411
|
end
|
|
414
412
|
|
|
@@ -416,6 +414,9 @@ class BreedResource < JSONAPI::Resource
|
|
|
416
414
|
attribute :id, format_misspelled: :does_not_exist
|
|
417
415
|
attribute :name, format: :title
|
|
418
416
|
|
|
417
|
+
# This is unneeded, just here for testing
|
|
418
|
+
routing_options :param => :id
|
|
419
|
+
|
|
419
420
|
def self.find(attrs, context = nil)
|
|
420
421
|
breeds = []
|
|
421
422
|
$breed_data.breeds.values.each do |breed|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
module Helpers
|
|
2
2
|
module HashHelpers
|
|
3
|
+
# :nocov:
|
|
3
4
|
def assert_hash_contains(exp, act, msg = nil)
|
|
4
5
|
msg = message(msg, '') { diff exp, act }
|
|
5
6
|
assert(matches_hash?(exp, act), msg)
|
|
@@ -9,5 +10,6 @@ module Helpers
|
|
|
9
10
|
msg = message(msg, '') { diff exp, act }
|
|
10
11
|
assert(matches_hash?(exp, act, {exact: true}), msg)
|
|
11
12
|
end
|
|
13
|
+
# :nocov:
|
|
12
14
|
end
|
|
13
|
-
end
|
|
15
|
+
end
|
|
@@ -111,6 +111,12 @@ class RoutesTest < ActionDispatch::IntegrationTest
|
|
|
111
111
|
{action: 'show', controller: 'api/v3/posts', id: '1'})
|
|
112
112
|
end
|
|
113
113
|
|
|
114
|
+
#primary_key
|
|
115
|
+
def test_routing_primary_key_jsonapi_resources
|
|
116
|
+
assert_routing({path: '/iso_currencies/USD', method: :get},
|
|
117
|
+
{action: 'show', controller: 'iso_currencies', code: 'USD'})
|
|
118
|
+
end
|
|
119
|
+
|
|
114
120
|
# ToDo: Refute routing
|
|
115
121
|
# def test_routing_v3_posts_delete
|
|
116
122
|
# assert_routing({ path: '/api/v3/posts/1', method: :delete },
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: jsonapi-resources
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.8
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Dan Gebhardt
|
|
@@ -9,7 +9,7 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2014-10-
|
|
12
|
+
date: 2014-10-21 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: bundler
|