jsonapi-resources 0.4.2 → 0.4.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +2 -2
- data/README.md +103 -71
- data/Rakefile +2 -2
- data/jsonapi-resources.gemspec +2 -2
- data/lib/jsonapi-resources.rb +0 -1
- data/lib/jsonapi/active_record_operations_processor.rb +10 -2
- data/lib/jsonapi/acts_as_resource_controller.rb +26 -24
- data/lib/jsonapi/association.rb +50 -15
- data/lib/jsonapi/callbacks.rb +1 -2
- data/lib/jsonapi/configuration.rb +8 -24
- data/lib/jsonapi/error.rb +1 -2
- data/lib/jsonapi/error_codes.rb +3 -1
- data/lib/jsonapi/exceptions.rb +59 -47
- data/lib/jsonapi/include_directives.rb +11 -11
- data/lib/jsonapi/mime_types.rb +2 -2
- data/lib/jsonapi/operation.rb +28 -11
- data/lib/jsonapi/operations_processor.rb +16 -5
- data/lib/jsonapi/paginator.rb +19 -19
- data/lib/jsonapi/request.rb +175 -196
- data/lib/jsonapi/resource.rb +158 -105
- data/lib/jsonapi/resource_serializer.rb +37 -26
- data/lib/jsonapi/resources/version.rb +2 -2
- data/lib/jsonapi/response_document.rb +5 -4
- data/lib/jsonapi/routing_ext.rb +24 -19
- data/test/controllers/controller_test.rb +261 -31
- data/test/fixtures/active_record.rb +206 -8
- data/test/fixtures/book_comments.yml +2 -1
- data/test/fixtures/books.yml +1 -0
- data/test/fixtures/documents.yml +3 -0
- data/test/fixtures/people.yml +8 -1
- data/test/fixtures/pictures.yml +15 -0
- data/test/fixtures/products.yml +3 -0
- data/test/fixtures/vehicles.yml +8 -0
- data/test/helpers/{hash_helpers.rb → assertions.rb} +6 -1
- data/test/integration/requests/request_test.rb +14 -3
- data/test/integration/routes/routes_test.rb +47 -0
- data/test/test_helper.rb +27 -4
- data/test/unit/serializer/include_directives_test.rb +5 -0
- data/test/unit/serializer/polymorphic_serializer_test.rb +384 -0
- data/test/unit/serializer/serializer_test.rb +19 -1
- metadata +14 -4
data/lib/jsonapi/resource.rb
CHANGED
@@ -6,7 +6,7 @@ module JSONAPI
|
|
6
6
|
|
7
7
|
@@resource_types = {}
|
8
8
|
|
9
|
-
|
9
|
+
attr_reader :context
|
10
10
|
attr_reader :model
|
11
11
|
|
12
12
|
define_jsonapi_resources_callbacks :create,
|
@@ -17,6 +17,7 @@ module JSONAPI
|
|
17
17
|
:replace_has_many_links,
|
18
18
|
:create_has_one_link,
|
19
19
|
:replace_has_one_link,
|
20
|
+
:replace_polymorphic_has_one_link,
|
20
21
|
:remove_has_many_link,
|
21
22
|
:remove_has_one_link,
|
22
23
|
:replace_fields
|
@@ -48,9 +49,7 @@ module JSONAPI
|
|
48
49
|
completed = (yield == :completed)
|
49
50
|
end
|
50
51
|
|
51
|
-
if @save_needed || is_new?
|
52
|
-
completed = (save == :completed)
|
53
|
-
end
|
52
|
+
completed = (save == :completed) if @save_needed || is_new?
|
54
53
|
end
|
55
54
|
end
|
56
55
|
|
@@ -81,6 +80,12 @@ module JSONAPI
|
|
81
80
|
end
|
82
81
|
end
|
83
82
|
|
83
|
+
def replace_polymorphic_has_one_link(association_type, association_key_value, association_key_type)
|
84
|
+
change :replace_polymorphic_has_one_link do
|
85
|
+
_replace_polymorphic_has_one_link(association_type, association_key_value, association_key_type)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
84
89
|
def remove_has_many_link(association_type, key)
|
85
90
|
change :remove_has_many_link do
|
86
91
|
_remove_has_many_link(association_type, key)
|
@@ -106,11 +111,12 @@ module JSONAPI
|
|
106
111
|
|
107
112
|
# Override this on a resource to customize how the associated records
|
108
113
|
# are fetched for a model. Particularly helpful for authorization.
|
109
|
-
def records_for(association_name,
|
114
|
+
def records_for(association_name, _options = {})
|
110
115
|
model.send association_name
|
111
116
|
end
|
112
117
|
|
113
118
|
private
|
119
|
+
|
114
120
|
def save
|
115
121
|
run_callbacks :save do
|
116
122
|
_save
|
@@ -132,45 +138,43 @@ module JSONAPI
|
|
132
138
|
# ```
|
133
139
|
def _save
|
134
140
|
unless @model.valid?
|
135
|
-
|
141
|
+
fail JSONAPI::Exceptions::ValidationErrors.new(@model.errors.messages)
|
136
142
|
end
|
137
143
|
|
138
144
|
if defined? @model.save
|
139
145
|
saved = @model.save
|
140
|
-
unless saved
|
141
|
-
raise JSONAPI::Exceptions::SaveFailed.new
|
142
|
-
end
|
146
|
+
fail JSONAPI::Exceptions::SaveFailed.new unless saved
|
143
147
|
else
|
144
148
|
saved = true
|
145
149
|
end
|
146
150
|
|
147
151
|
@save_needed = !saved
|
148
152
|
|
149
|
-
|
153
|
+
:completed
|
150
154
|
end
|
151
155
|
|
152
156
|
def _remove
|
153
157
|
@model.destroy
|
154
158
|
|
155
|
-
|
159
|
+
:completed
|
156
160
|
end
|
157
161
|
|
158
162
|
def _create_has_many_links(association_type, association_key_values)
|
159
163
|
association = self.class._associations[association_type]
|
160
164
|
|
161
165
|
association_key_values.each do |association_key_value|
|
162
|
-
related_resource =
|
166
|
+
related_resource = association.resource_klass.find_by_key(association_key_value, context: @context)
|
163
167
|
|
164
|
-
#
|
168
|
+
# TODO: Add option to skip relations that already exist instead of returning an error?
|
165
169
|
relation = @model.send(association.type).where(association.primary_key => association_key_value).first
|
166
170
|
if relation.nil?
|
167
171
|
@model.send(association.type) << related_resource.model
|
168
172
|
else
|
169
|
-
|
173
|
+
fail JSONAPI::Exceptions::HasManyRelationExists.new(association_key_value)
|
170
174
|
end
|
171
175
|
end
|
172
176
|
|
173
|
-
|
177
|
+
:completed
|
174
178
|
end
|
175
179
|
|
176
180
|
def _replace_has_many_links(association_type, association_key_values)
|
@@ -179,7 +183,7 @@ module JSONAPI
|
|
179
183
|
send("#{association.foreign_key}=", association_key_values)
|
180
184
|
@save_needed = true
|
181
185
|
|
182
|
-
|
186
|
+
:completed
|
183
187
|
end
|
184
188
|
|
185
189
|
def _replace_has_one_link(association_type, association_key_value)
|
@@ -188,7 +192,18 @@ module JSONAPI
|
|
188
192
|
send("#{association.foreign_key}=", association_key_value)
|
189
193
|
@save_needed = true
|
190
194
|
|
191
|
-
|
195
|
+
:completed
|
196
|
+
end
|
197
|
+
|
198
|
+
def _replace_polymorphic_has_one_link(association_type, key_value, key_type)
|
199
|
+
association = self.class._associations[association_type.to_sym]
|
200
|
+
|
201
|
+
model.send("#{association.foreign_key}=", key_value)
|
202
|
+
model.send("#{association.polymorphic_type}=", key_type.to_s.classify)
|
203
|
+
|
204
|
+
@save_needed = true
|
205
|
+
|
206
|
+
:completed
|
192
207
|
end
|
193
208
|
|
194
209
|
def _remove_has_many_link(association_type, key)
|
@@ -196,7 +211,7 @@ module JSONAPI
|
|
196
211
|
|
197
212
|
@model.send(association.type).delete(key)
|
198
213
|
|
199
|
-
|
214
|
+
:completed
|
200
215
|
end
|
201
216
|
|
202
217
|
def _remove_has_one_link(association_type)
|
@@ -205,7 +220,7 @@ module JSONAPI
|
|
205
220
|
send("#{association.foreign_key}=", nil)
|
206
221
|
@save_needed = true
|
207
222
|
|
208
|
-
|
223
|
+
:completed
|
209
224
|
end
|
210
225
|
|
211
226
|
def _replace_fields(field_data)
|
@@ -224,7 +239,12 @@ module JSONAPI
|
|
224
239
|
if value.nil?
|
225
240
|
remove_has_one_link(association_type)
|
226
241
|
else
|
227
|
-
|
242
|
+
case value
|
243
|
+
when Hash
|
244
|
+
replace_polymorphic_has_one_link(association_type.to_s, value.fetch(:id), value.fetch(:type))
|
245
|
+
else
|
246
|
+
replace_has_one_link(association_type, value)
|
247
|
+
end
|
228
248
|
end
|
229
249
|
end if field_data[:has_one]
|
230
250
|
|
@@ -232,7 +252,7 @@ module JSONAPI
|
|
232
252
|
replace_has_many_links(association_type, values)
|
233
253
|
end if field_data[:has_many]
|
234
254
|
|
235
|
-
|
255
|
+
:completed
|
236
256
|
end
|
237
257
|
|
238
258
|
class << self
|
@@ -253,15 +273,15 @@ module JSONAPI
|
|
253
273
|
resource_name = JSONAPI::Resource._resource_name_from_type(type)
|
254
274
|
resource = resource_name.safe_constantize if resource_name
|
255
275
|
if resource.nil?
|
256
|
-
|
276
|
+
fail NameError, "JSONAPI: Could not find resource '#{type}'. (Class #{resource_name} not found)"
|
257
277
|
end
|
258
278
|
resource
|
259
279
|
end
|
260
280
|
|
261
|
-
attr_accessor :_attributes, :_associations, :_allowed_filters
|
281
|
+
attr_accessor :_attributes, :_associations, :_allowed_filters, :_type, :_paginator
|
262
282
|
|
263
283
|
def create(context)
|
264
|
-
|
284
|
+
new(create_model, context)
|
265
285
|
end
|
266
286
|
|
267
287
|
def create_model
|
@@ -303,7 +323,7 @@ module JSONAPI
|
|
303
323
|
end
|
304
324
|
|
305
325
|
def default_attribute_options
|
306
|
-
{format: :default}
|
326
|
+
{ format: :default }
|
307
327
|
end
|
308
328
|
|
309
329
|
def has_one(*attrs)
|
@@ -319,7 +339,7 @@ module JSONAPI
|
|
319
339
|
end
|
320
340
|
|
321
341
|
def filters(*attrs)
|
322
|
-
@_allowed_filters.merge!(attrs.inject(
|
342
|
+
@_allowed_filters.merge!(attrs.inject({}) { |h, attr| h[attr] = {}; h })
|
323
343
|
end
|
324
344
|
|
325
345
|
def filter(attr, *args)
|
@@ -334,11 +354,11 @@ module JSONAPI
|
|
334
354
|
# :nocov:
|
335
355
|
def method_missing(method, *args)
|
336
356
|
if method.to_s.match /createable_fields/
|
337
|
-
ActiveSupport::Deprecation.warn(
|
338
|
-
|
357
|
+
ActiveSupport::Deprecation.warn('`createable_fields` is deprecated, please use `creatable_fields` instead')
|
358
|
+
creatable_fields(*args)
|
339
359
|
elsif method.to_s.match /updateable_fields/
|
340
|
-
ActiveSupport::Deprecation.warn(
|
341
|
-
|
360
|
+
ActiveSupport::Deprecation.warn('`updateable_fields` is deprecated, please use `updatable_fields` instead')
|
361
|
+
updatable_fields(*args)
|
342
362
|
else
|
343
363
|
super
|
344
364
|
end
|
@@ -346,17 +366,17 @@ module JSONAPI
|
|
346
366
|
# :nocov:
|
347
367
|
|
348
368
|
# Override in your resource to filter the updatable keys
|
349
|
-
def updatable_fields(
|
369
|
+
def updatable_fields(_context = nil)
|
350
370
|
_updatable_associations | _attributes.keys - [:id]
|
351
371
|
end
|
352
372
|
|
353
373
|
# Override in your resource to filter the creatable keys
|
354
|
-
def creatable_fields(
|
374
|
+
def creatable_fields(_context = nil)
|
355
375
|
_updatable_associations | _attributes.keys
|
356
376
|
end
|
357
377
|
|
358
378
|
# Override in your resource to filter the sortable keys
|
359
|
-
def sortable_fields(
|
379
|
+
def sortable_fields(_context = nil)
|
360
380
|
_attributes.keys
|
361
381
|
end
|
362
382
|
|
@@ -364,15 +384,38 @@ module JSONAPI
|
|
364
384
|
_associations.keys | _attributes.keys
|
365
385
|
end
|
366
386
|
|
367
|
-
def
|
368
|
-
|
387
|
+
def resolve_association_names_to_relations(resource_klass, model_includes, options = {})
|
388
|
+
case model_includes
|
389
|
+
when Array
|
390
|
+
return model_includes.map do |value|
|
391
|
+
resolve_association_names_to_relations(resource_klass, value, options)
|
392
|
+
end
|
393
|
+
when Hash
|
394
|
+
model_includes.keys.each do |key|
|
395
|
+
association = resource_klass._associations[key]
|
396
|
+
value = model_includes[key]
|
397
|
+
model_includes.delete(key)
|
398
|
+
model_includes[association.relation_name(options)] = resolve_association_names_to_relations(association.resource_klass, value, options)
|
399
|
+
end
|
400
|
+
return model_includes
|
401
|
+
when Symbol
|
402
|
+
association = resource_klass._associations[model_includes]
|
403
|
+
return association.relation_name(options)
|
404
|
+
end
|
405
|
+
end
|
406
|
+
|
407
|
+
def apply_includes(records, options = {})
|
408
|
+
include_directives = options[:include_directives]
|
409
|
+
if include_directives
|
410
|
+
model_includes = resolve_association_names_to_relations(self, include_directives.model_includes, options)
|
411
|
+
records = records.includes(model_includes)
|
412
|
+
end
|
413
|
+
|
369
414
|
records
|
370
415
|
end
|
371
416
|
|
372
417
|
def apply_pagination(records, paginator, order_options)
|
373
|
-
if paginator
|
374
|
-
records = paginator.apply(records, order_options)
|
375
|
-
end
|
418
|
+
records = paginator.apply(records, order_options) if paginator
|
376
419
|
records
|
377
420
|
end
|
378
421
|
|
@@ -384,7 +427,7 @@ module JSONAPI
|
|
384
427
|
end
|
385
428
|
end
|
386
429
|
|
387
|
-
def apply_filter(records, filter, value,
|
430
|
+
def apply_filter(records, filter, value, _options = {})
|
388
431
|
records.where(filter => value)
|
389
432
|
end
|
390
433
|
|
@@ -395,7 +438,7 @@ module JSONAPI
|
|
395
438
|
filters.each do |filter, value|
|
396
439
|
if _associations.include?(filter)
|
397
440
|
if _associations[filter].is_a?(JSONAPI::Association::HasMany)
|
398
|
-
required_includes.push(filter)
|
441
|
+
required_includes.push(filter.to_s)
|
399
442
|
records = apply_filter(records, "#{filter}.#{_associations[filter].primary_key}", value, options)
|
400
443
|
else
|
401
444
|
records = apply_filter(records, "#{_associations[filter].foreign_key}", value, options)
|
@@ -407,20 +450,16 @@ module JSONAPI
|
|
407
450
|
end
|
408
451
|
|
409
452
|
if required_includes.any?
|
410
|
-
records.
|
411
|
-
elsif records.respond_to? :to_ary
|
412
|
-
records
|
413
|
-
else
|
414
|
-
records.all
|
453
|
+
records = apply_includes(records, options.merge(include_directives: IncludeDirectives.new(required_includes)))
|
415
454
|
end
|
455
|
+
|
456
|
+
records
|
416
457
|
end
|
417
458
|
|
418
459
|
def filter_records(filters, options)
|
419
|
-
include_directives = options[:include_directives]
|
420
|
-
|
421
460
|
records = records(options)
|
422
|
-
records =
|
423
|
-
|
461
|
+
records = apply_filters(records, filters, options)
|
462
|
+
apply_includes(records, options)
|
424
463
|
end
|
425
464
|
|
426
465
|
def sort_records(records, order_options)
|
@@ -445,27 +484,24 @@ module JSONAPI
|
|
445
484
|
|
446
485
|
resources = []
|
447
486
|
records.each do |model|
|
448
|
-
resources.push
|
487
|
+
resources.push new(model, context)
|
449
488
|
end
|
450
489
|
|
451
|
-
|
490
|
+
resources
|
452
491
|
end
|
453
492
|
|
454
493
|
def find_by_key(key, options = {})
|
455
494
|
context = options[:context]
|
456
|
-
include_directives = options[:include_directives]
|
457
495
|
records = records(options)
|
458
|
-
records = apply_includes(records,
|
496
|
+
records = apply_includes(records, options)
|
459
497
|
model = records.where({_primary_key => key}).first
|
460
|
-
if model.nil?
|
461
|
-
|
462
|
-
end
|
463
|
-
self.new(model, context)
|
498
|
+
fail JSONAPI::Exceptions::RecordNotFound.new(key) if model.nil?
|
499
|
+
new(model, context)
|
464
500
|
end
|
465
501
|
|
466
502
|
# Override this method if you want to customize the relation for
|
467
503
|
# finder methods (find, find_by_key)
|
468
|
-
def records(
|
504
|
+
def records(_options = {})
|
469
505
|
_model_class
|
470
506
|
end
|
471
507
|
|
@@ -494,7 +530,7 @@ module JSONAPI
|
|
494
530
|
end
|
495
531
|
|
496
532
|
# override to allow for key processing and checking
|
497
|
-
def verify_key(key,
|
533
|
+
def verify_key(key, _context = nil)
|
498
534
|
key && Integer(key)
|
499
535
|
rescue
|
500
536
|
raise JSONAPI::Exceptions::InvalidFieldValue.new(:id, key)
|
@@ -508,13 +544,13 @@ module JSONAPI
|
|
508
544
|
end
|
509
545
|
|
510
546
|
# override to allow for custom filters
|
511
|
-
def verify_custom_filter(filter, value,
|
512
|
-
|
547
|
+
def verify_custom_filter(filter, value, _context = nil)
|
548
|
+
[filter, value]
|
513
549
|
end
|
514
550
|
|
515
551
|
# override to allow for custom association logic, such as uuids, multiple keys or permission checks on keys
|
516
|
-
def verify_association_filter(filter, raw,
|
517
|
-
|
552
|
+
def verify_association_filter(filter, raw, _context = nil)
|
553
|
+
[filter, raw]
|
518
554
|
end
|
519
555
|
|
520
556
|
# quasi private class methods
|
@@ -523,12 +559,12 @@ module JSONAPI
|
|
523
559
|
end
|
524
560
|
|
525
561
|
def _updatable_associations
|
526
|
-
@_associations.map { |key,
|
562
|
+
@_associations.map { |key, _association| key }
|
527
563
|
end
|
528
564
|
|
529
565
|
def _has_association?(type)
|
530
566
|
type = type.to_s
|
531
|
-
@_associations.
|
567
|
+
@_associations.key?(type.singularize.to_sym) || @_associations.key?(type.pluralize.to_sym)
|
532
568
|
end
|
533
569
|
|
534
570
|
def _association(type)
|
@@ -537,7 +573,7 @@ module JSONAPI
|
|
537
573
|
end
|
538
574
|
|
539
575
|
def _model_name
|
540
|
-
@_model_name ||=
|
576
|
+
@_model_name ||= name.demodulize.sub(/Resource$/, '')
|
541
577
|
end
|
542
578
|
|
543
579
|
def _primary_key
|
@@ -549,13 +585,13 @@ module JSONAPI
|
|
549
585
|
end
|
550
586
|
|
551
587
|
def _allowed_filters
|
552
|
-
!@_allowed_filters.nil? ? @_allowed_filters : { :
|
588
|
+
!@_allowed_filters.nil? ? @_allowed_filters : { id: {} }
|
553
589
|
end
|
554
590
|
|
555
591
|
def _resource_name_from_type(type)
|
556
592
|
class_name = @@resource_types[type]
|
557
593
|
if class_name.nil?
|
558
|
-
class_name = "#{type.to_s.singularize}_resource".camelize
|
594
|
+
class_name = "#{type.to_s.underscore.singularize}_resource".camelize
|
559
595
|
@@resource_types[type] = class_name
|
560
596
|
end
|
561
597
|
return class_name
|
@@ -578,19 +614,20 @@ module JSONAPI
|
|
578
614
|
end
|
579
615
|
|
580
616
|
def module_path
|
581
|
-
@module_path ||=
|
617
|
+
@module_path ||= name =~ /::[^:]+\Z/ ? ($`.freeze.gsub('::', '/') + '/').downcase : ''
|
582
618
|
end
|
583
619
|
|
584
620
|
def construct_order_options(sort_params)
|
585
621
|
return {} unless sort_params
|
586
622
|
|
587
|
-
sort_params.each_with_object({})
|
623
|
+
sort_params.each_with_object({}) do |sort, order_hash|
|
588
624
|
field = sort[:field] == 'id' ? _primary_key : sort[:field]
|
589
625
|
order_hash[field] = sort[:direction]
|
590
|
-
|
626
|
+
end
|
591
627
|
end
|
592
628
|
|
593
629
|
private
|
630
|
+
|
594
631
|
def check_reserved_resource_name(type, name)
|
595
632
|
if [:ids, :types, :hrefs, :links].include?(type)
|
596
633
|
warn "[NAME COLLISION] `#{name}` is a reserved resource name."
|
@@ -618,63 +655,79 @@ module JSONAPI
|
|
618
655
|
|
619
656
|
attrs.each do |attr|
|
620
657
|
check_reserved_association_name(attr)
|
658
|
+
@_associations[attr] = association = klass.new(attr, options)
|
621
659
|
|
622
|
-
|
660
|
+
associated_records_method_name = case association
|
661
|
+
when JSONAPI::Association::HasOne then "record_for_#{attr}"
|
662
|
+
when JSONAPI::Association::HasMany then "records_for_#{attr}"
|
663
|
+
end
|
623
664
|
|
624
|
-
foreign_key =
|
625
|
-
|
626
|
-
define_method foreign_key do
|
627
|
-
@model.method(foreign_key).call
|
628
|
-
end unless method_defined?(foreign_key)
|
665
|
+
foreign_key = association.foreign_key
|
629
666
|
|
630
667
|
define_method "#{foreign_key}=" do |value|
|
631
668
|
@model.method("#{foreign_key}=").call(value)
|
632
669
|
end unless method_defined?("#{foreign_key}=")
|
633
670
|
|
634
|
-
associated_records_method_name =
|
635
|
-
|
636
|
-
|
637
|
-
end
|
638
|
-
|
639
|
-
define_method associated_records_method_name do |options={}|
|
640
|
-
records_for(attr, options)
|
671
|
+
define_method associated_records_method_name do |options = {}|
|
672
|
+
relation_name = association.relation_name(options.merge({context: @context}))
|
673
|
+
records_for(relation_name, options)
|
641
674
|
end unless method_defined?(associated_records_method_name)
|
642
675
|
|
643
|
-
if
|
644
|
-
define_method
|
645
|
-
|
646
|
-
|
647
|
-
|
676
|
+
if association.is_a?(JSONAPI::Association::HasOne)
|
677
|
+
define_method foreign_key do
|
678
|
+
@model.method(foreign_key).call
|
679
|
+
end unless method_defined?(foreign_key)
|
680
|
+
|
681
|
+
define_method attr do |options = {}|
|
682
|
+
if association.polymorphic?
|
648
683
|
associated_model = public_send(associated_records_method_name)
|
649
|
-
|
684
|
+
resource_klass = Resource.resource_for(self.class.module_path + associated_model.class.to_s.underscore) if associated_model
|
685
|
+
return resource_klass.new(associated_model, @context) if resource_klass
|
686
|
+
else
|
687
|
+
resource_klass = association.resource_klass
|
688
|
+
if resource_klass
|
689
|
+
associated_model = public_send(associated_records_method_name)
|
690
|
+
return associated_model ? resource_klass.new(associated_model, @context) : nil
|
691
|
+
end
|
650
692
|
end
|
651
693
|
end unless method_defined?(attr)
|
652
|
-
elsif
|
694
|
+
elsif association.is_a?(JSONAPI::Association::HasMany)
|
695
|
+
define_method foreign_key do
|
696
|
+
records = public_send(associated_records_method_name)
|
697
|
+
return records.collect do |record|
|
698
|
+
record.send(association.resource_klass._primary_key)
|
699
|
+
end
|
700
|
+
end unless method_defined?(foreign_key)
|
653
701
|
define_method attr do |options = {}|
|
654
|
-
|
655
|
-
|
702
|
+
resource_klass = association.resource_klass
|
703
|
+
records = public_send(associated_records_method_name)
|
704
|
+
|
656
705
|
filters = options.fetch(:filters, {})
|
706
|
+
unless filters.nil? || filters.empty?
|
707
|
+
records = resource_klass.apply_filters(records, filters, options)
|
708
|
+
end
|
709
|
+
|
657
710
|
sort_criteria = options.fetch(:sort_criteria, {})
|
658
|
-
|
711
|
+
unless sort_criteria.nil? || sort_criteria.empty?
|
712
|
+
order_options = self.class.construct_order_options(sort_criteria)
|
713
|
+
records = resource_klass.apply_sort(records, order_options)
|
714
|
+
end
|
659
715
|
|
660
|
-
|
716
|
+
paginator = options[:paginator]
|
717
|
+
if paginator
|
718
|
+
records = resource_klass.apply_pagination(records, paginator, order_options)
|
719
|
+
end
|
661
720
|
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
order_options = self.class.construct_order_options(sort_criteria)
|
666
|
-
records = resource_class.apply_sort(records, order_options)
|
667
|
-
records = resource_class.apply_pagination(records, paginator, order_options)
|
668
|
-
records.each do |record|
|
669
|
-
resources.push resource_class.new(record, @context)
|
721
|
+
return records.collect do |record|
|
722
|
+
if association.polymorphic?
|
723
|
+
resource_klass = Resource.resource_for(self.class.module_path + record.class.to_s.underscore)
|
670
724
|
end
|
725
|
+
resource_klass.new(record, @context)
|
671
726
|
end
|
672
|
-
return resources
|
673
727
|
end unless method_defined?(attr)
|
674
728
|
end
|
675
729
|
end
|
676
730
|
end
|
677
731
|
end
|
678
|
-
|
679
732
|
end
|
680
733
|
end
|