jsonapi-resources 0.9.0 → 0.9.12

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.
@@ -90,20 +90,19 @@ module JSONAPI
90
90
  primary_hash
91
91
  end
92
92
 
93
- def serialize_to_links_hash(source, requested_relationship)
93
+ def serialize_to_relationship_hash(source, requested_relationship)
94
94
  if requested_relationship.is_a?(JSONAPI::Relationship::ToOne)
95
95
  data = to_one_linkage(source, requested_relationship)
96
96
  else
97
97
  data = to_many_linkage(source, requested_relationship)
98
98
  end
99
99
 
100
- {
101
- links: {
102
- self: self_link(source, requested_relationship),
103
- related: related_link(source, requested_relationship)
104
- },
105
- data: data
106
- }
100
+ rel_hash = { 'data': data }
101
+
102
+ links = default_relationship_links(source, requested_relationship)
103
+ rel_hash['links'] = links unless links.blank?
104
+
105
+ rel_hash
107
106
  end
108
107
 
109
108
  def query_link(query_params)
@@ -133,7 +132,6 @@ module JSONAPI
133
132
  supplying_attribute_fields: supplying_attribute_fields(resource_klass).sort,
134
133
  supplying_relationship_fields: supplying_relationship_fields(resource_klass).sort,
135
134
  link_builder_base_url: link_builder.base_url,
136
- route_formatter_class: link_builder.route_formatter.uncached.class.name,
137
135
  key_formatter_class: key_formatter.uncached.class.name,
138
136
  always_include_to_one_linkage_data: always_include_to_one_linkage_data,
139
137
  always_include_to_many_linkage_data: always_include_to_many_linkage_data
@@ -152,7 +150,7 @@ module JSONAPI
152
150
  obj_hash['attributes'] = source.attributes_json if source.attributes_json
153
151
 
154
152
  relationships = cached_relationships_hash(source, include_directives)
155
- obj_hash['relationships'] = relationships unless relationships.empty?
153
+ obj_hash['relationships'] = relationships unless relationships.blank?
156
154
 
157
155
  obj_hash['meta'] = source.meta_json if source.meta_json
158
156
  else
@@ -173,7 +171,7 @@ module JSONAPI
173
171
  obj_hash['attributes'] = attributes unless attributes.empty?
174
172
 
175
173
  relationships = relationships_hash(source, fetchable_fields, include_directives)
176
- obj_hash['relationships'] = relationships unless relationships.nil? || relationships.empty?
174
+ obj_hash['relationships'] = relationships unless relationships.blank?
177
175
 
178
176
  meta = meta_hash(source)
179
177
  obj_hash['meta'] = meta unless meta.empty?
@@ -251,7 +249,9 @@ module JSONAPI
251
249
 
252
250
  def links_hash(source)
253
251
  links = custom_links_hash(source)
254
- links[:self] = link_builder.self_link(source) unless links.key?(:self)
252
+ if !links.key?('self') && !source.class.exclude_link?(:self)
253
+ links['self'] = link_builder.self_link(source)
254
+ end
255
255
  links.compact
256
256
  end
257
257
 
@@ -288,7 +288,8 @@ module JSONAPI
288
288
  include_linked_children = ia && !ia[:include_related].empty?
289
289
 
290
290
  if field_set.include?(name)
291
- hash[format_key(name)] = link_object(source, relationship, include_linkage)
291
+ ro = relationship_object(source, relationship, include_linkage)
292
+ hash[format_key(name)] = ro unless ro.blank?
292
293
  end
293
294
 
294
295
  # If the object has been serialized once it will be in the related objects list,
@@ -298,7 +299,8 @@ module JSONAPI
298
299
  resources = if source.preloaded_fragments.has_key?(format_key(name))
299
300
  source.preloaded_fragments[format_key(name)].values
300
301
  else
301
- [source.public_send(name)].flatten(1).compact
302
+ options = { filters: ia && ia[:include_filters] || {} }
303
+ [source.public_send(name, options)].flatten(1).compact
302
304
  end
303
305
  resources.each do |resource|
304
306
  next if self_referential_and_already_in_source(resource)
@@ -380,6 +382,13 @@ module JSONAPI
380
382
  link_builder.relationships_related_link(source, relationship)
381
383
  end
382
384
 
385
+ def default_relationship_links(source, relationship)
386
+ links = {}
387
+ links['self'] = self_link(source, relationship) unless relationship.exclude_link?(:self)
388
+ links['related'] = related_link(source, relationship) unless relationship.exclude_link?(:related)
389
+ links.compact
390
+ end
391
+
383
392
  def to_one_linkage(source, relationship)
384
393
  linkage_id = foreign_key_value(source, relationship)
385
394
  linkage_type = format_key(relationship.type_for_source(source))
@@ -393,24 +402,29 @@ module JSONAPI
393
402
 
394
403
  def to_many_linkage(source, relationship)
395
404
  linkage = []
405
+ include_config = include_directives.include_config(relationship.name.to_sym) if include_directives
406
+ include_filters = include_config[:include_filters] if include_config
407
+ options = { filters: include_filters || {} }
408
+
396
409
  linkage_types_and_values = if source.preloaded_fragments.has_key?(format_key(relationship.name))
397
410
  source.preloaded_fragments[format_key(relationship.name)].map do |_, resource|
398
411
  [relationship.type, resource.id]
399
412
  end
400
413
  elsif relationship.polymorphic?
401
- assoc = source._model.public_send(relationship.name)
414
+ assoc = source.public_send("records_for_#{relationship.name}", options)
402
415
  # Avoid hitting the database again for values already pre-loaded
403
416
  if assoc.respond_to?(:loaded?) and assoc.loaded?
404
417
  assoc.map do |obj|
405
418
  [obj.type.underscore.pluralize, obj.id]
406
419
  end
407
420
  else
421
+ assoc = assoc.unscope(:includes) if assoc.is_a?(ActiveRecord::Relation)
408
422
  assoc.pluck(:type, :id).map do |type, id|
409
423
  [type.underscore.pluralize, id]
410
424
  end
411
425
  end
412
426
  else
413
- source.public_send(relationship.name).map do |value|
427
+ source.public_send(relationship.name, options).map do |value|
414
428
  [relationship.type, value.id]
415
429
  end
416
430
  end
@@ -423,46 +437,51 @@ module JSONAPI
423
437
  linkage
424
438
  end
425
439
 
426
- def link_object_to_one(source, relationship, include_linkage)
440
+ def relationship_object_to_one(source, relationship, include_linkage)
427
441
  include_linkage = include_linkage | @always_include_to_one_linkage_data | relationship.always_include_linkage_data
428
- link_object_hash = {}
429
- link_object_hash[:links] = {}
430
- link_object_hash[:links][:self] = self_link(source, relationship)
431
- link_object_hash[:links][:related] = related_link(source, relationship)
432
- link_object_hash[:data] = to_one_linkage(source, relationship) if include_linkage
433
- link_object_hash
442
+ relationship_object_hash = {}
443
+
444
+ links = default_relationship_links(source, relationship)
445
+
446
+ relationship_object_hash['links'] = links unless links.blank?
447
+ relationship_object_hash[:data] = to_one_linkage(source, relationship) if include_linkage
448
+ relationship_object_hash
434
449
  end
435
450
 
436
- def link_object_to_many(source, relationship, include_linkage)
451
+ def relationship_object_to_many(source, relationship, include_linkage)
437
452
  include_linkage = include_linkage | relationship.always_include_linkage_data
438
- link_object_hash = {}
439
- link_object_hash[:links] = {}
440
- link_object_hash[:links][:self] = self_link(source, relationship)
441
- link_object_hash[:links][:related] = related_link(source, relationship)
442
- link_object_hash[:data] = to_many_linkage(source, relationship) if include_linkage
443
- link_object_hash
453
+ relationship_object_hash = {}
454
+
455
+ links = default_relationship_links(source, relationship)
456
+ relationship_object_hash['links'] = links unless links.blank?
457
+ relationship_object_hash[:data] = to_many_linkage(source, relationship) if include_linkage
458
+ relationship_object_hash
444
459
  end
445
460
 
446
- def link_object(source, relationship, include_linkage = false)
461
+ def relationship_object(source, relationship, include_linkage = false)
447
462
  if relationship.is_a?(JSONAPI::Relationship::ToOne)
448
- link_object_to_one(source, relationship, include_linkage)
463
+ relationship_object_to_one(source, relationship, include_linkage)
449
464
  elsif relationship.is_a?(JSONAPI::Relationship::ToMany)
450
- link_object_to_many(source, relationship, include_linkage)
465
+ relationship_object_to_many(source, relationship, include_linkage)
451
466
  end
452
467
  end
453
468
 
454
469
  # Extracts the foreign key value for a to_one relationship.
455
470
  def foreign_key_value(source, relationship)
456
- related_resource_id = if source.preloaded_fragments.has_key?(format_key(relationship.name))
457
- source.preloaded_fragments[format_key(relationship.name)].values.first.try(:id)
458
- elsif source.respond_to?("#{relationship.name}_id")
459
- # If you have direct access to the underlying id, you don't have to load the relationship
460
- # which can save quite a lot of time when loading a lot of data.
461
- # This does not apply to e.g. has_one :through relationships.
462
- source.public_send("#{relationship.name}_id")
463
- else
464
- source.public_send(relationship.name).try(:id)
465
- end
471
+ # If you have changed the key_name, don't even try to look at `"#{relationship.name}_id"`
472
+ # just load the association and call the custom key_name
473
+ foreign_key_type_changed = relationship.options[:foreign_key_type_changed] || false
474
+ related_resource_id =
475
+ if source.preloaded_fragments.has_key?(format_key(relationship.name))
476
+ source.preloaded_fragments[format_key(relationship.name)].values.first.try(:id)
477
+ elsif !foreign_key_type_changed && source.respond_to?("#{relationship.name}_id")
478
+ # If you have direct access to the underlying id, you don't have to load the relationship
479
+ # which can save quite a lot of time when loading a lot of data.
480
+ # This does not apply to e.g. has_one :through relationships.
481
+ source.public_send("#{relationship.name}_id")
482
+ else
483
+ source.public_send(relationship.name).try(:id)
484
+ end
466
485
  return nil unless related_resource_id
467
486
  @id_formatter.format(related_resource_id)
468
487
  end
@@ -523,8 +542,9 @@ module JSONAPI
523
542
  def generate_link_builder(primary_resource_klass, options)
524
543
  LinkBuilder.new(
525
544
  base_url: options.fetch(:base_url, ''),
526
- route_formatter: options.fetch(:route_formatter, JSONAPI.configuration.route_formatter),
527
545
  primary_resource_klass: primary_resource_klass,
546
+ route_formatter: options.fetch(:route_formatter, JSONAPI.configuration.route_formatter),
547
+ url_helpers: options.fetch(:url_helpers, options[:controller]),
528
548
  )
529
549
  end
530
550
  end
@@ -1,5 +1,5 @@
1
1
  module JSONAPI
2
2
  module Resources
3
- VERSION = '0.9.0'
3
+ VERSION = '0.9.12'
4
4
  end
5
5
  end
@@ -64,14 +64,19 @@ module JSONAPI
64
64
 
65
65
  # Build pagination links
66
66
  if result.is_a?(JSONAPI::ResourcesOperationResult) || result.is_a?(JSONAPI::RelatedResourcesOperationResult)
67
- result.pagination_params.each_pair do |link_name, params|
68
- if result.is_a?(JSONAPI::RelatedResourcesOperationResult)
69
- relationship = result.source_resource.class._relationships[result._type.to_sym]
70
- links[link_name] = @serializer.link_builder.relationships_related_link(result.source_resource, relationship, query_params(params))
71
- else
72
- links[link_name] = @serializer.query_link(query_params(params))
67
+ result.pagination_params.each_pair do |link_name, params|
68
+ if result.is_a?(JSONAPI::RelatedResourcesOperationResult)
69
+ relationship = result.source_resource.class._relationships[result._type.to_sym]
70
+ unless relationship.exclude_link?(link_name)
71
+ link = @serializer.link_builder.relationships_related_link(result.source_resource, relationship, query_params(params))
72
+ end
73
+ else
74
+ unless @serializer.link_builder.primary_resource_klass.exclude_link?(link_name)
75
+ link = @serializer.link_builder.query_link(query_params(params))
73
76
  end
74
77
  end
78
+ links[link_name] = link unless link.blank?
79
+ end
75
80
  end
76
81
  end
77
82
 
@@ -109,9 +114,9 @@ module JSONAPI
109
114
  @serializer.serialize_to_hash(result.resource)
110
115
  when JSONAPI::ResourcesOperationResult
111
116
  @serializer.serialize_to_hash(result.resources)
112
- when JSONAPI::LinksObjectOperationResult
113
- @serializer.serialize_to_links_hash(result.parent_resource,
114
- result.relationship)
117
+ when JSONAPI::RelationshipOperationResult
118
+ @serializer.serialize_to_relationship_hash(result.parent_resource,
119
+ result.relationship)
115
120
  when JSONAPI::OperationResult
116
121
  {}
117
122
  end
@@ -20,6 +20,12 @@ module ActionDispatch
20
20
  @resource_type = resources.first
21
21
  res = JSONAPI::Resource.resource_for(resource_type_with_module_prefix(@resource_type))
22
22
 
23
+ res._routed = true
24
+
25
+ unless res.singleton?
26
+ warn "Singleton routes created for non singleton resource #{res}. Links may not be generated correctly."
27
+ end
28
+
23
29
  options = resources.extract_options!.dup
24
30
  options[:controller] ||= @resource_type
25
31
  options.merge!(res.routing_resource_options)
@@ -80,6 +86,12 @@ module ActionDispatch
80
86
  @resource_type = resources.first
81
87
  res = JSONAPI::Resource.resource_for(resource_type_with_module_prefix(@resource_type))
82
88
 
89
+ res._routed = true
90
+
91
+ if res.singleton?
92
+ warn "Singleton resource #{res} should use `jsonapi_resource` instead."
93
+ end
94
+
83
95
  options = resources.extract_options!.dup
84
96
  options[:controller] ||= @resource_type
85
97
  options.merge!(res.routing_resource_options)
@@ -153,19 +165,23 @@ module ActionDispatch
153
165
  methods = links_methods(options)
154
166
 
155
167
  if methods.include?(:show)
156
- match "relationships/#{formatted_relationship_name}", controller: options[:controller],
157
- action: 'show_relationship', relationship: link_type.to_s, via: [:get]
168
+ match "relationships/#{formatted_relationship_name}",
169
+ controller: options[:controller],
170
+ action: 'show_relationship', relationship: link_type.to_s, via: [:get],
171
+ as: "relationships/#{link_type}"
158
172
  end
159
173
 
160
174
  if res.mutable?
161
175
  if methods.include?(:update)
162
- match "relationships/#{formatted_relationship_name}", controller: options[:controller],
163
- action: 'update_relationship', relationship: link_type.to_s, via: [:put, :patch]
176
+ match "relationships/#{formatted_relationship_name}",
177
+ controller: options[:controller],
178
+ action: 'update_relationship', relationship: link_type.to_s, via: [:put, :patch]
164
179
  end
165
180
 
166
181
  if methods.include?(:destroy)
167
- match "relationships/#{formatted_relationship_name}", controller: options[:controller],
168
- action: 'destroy_relationship', relationship: link_type.to_s, via: [:delete]
182
+ match "relationships/#{formatted_relationship_name}",
183
+ controller: options[:controller],
184
+ action: 'destroy_relationship', relationship: link_type.to_s, via: [:delete]
169
185
  end
170
186
  end
171
187
  end
@@ -182,23 +198,24 @@ module ActionDispatch
182
198
 
183
199
  if methods.include?(:show)
184
200
  match "relationships/#{formatted_relationship_name}", controller: options[:controller],
185
- action: 'show_relationship', relationship: link_type.to_s, via: [:get]
201
+ action: 'show_relationship', relationship: link_type.to_s, via: [:get],
202
+ as: "relationships/#{link_type}"
186
203
  end
187
204
 
188
205
  if res.mutable?
189
206
  if methods.include?(:create)
190
207
  match "relationships/#{formatted_relationship_name}", controller: options[:controller],
191
- action: 'create_relationship', relationship: link_type.to_s, via: [:post]
208
+ action: 'create_relationship', relationship: link_type.to_s, via: [:post]
192
209
  end
193
210
 
194
211
  if methods.include?(:update)
195
212
  match "relationships/#{formatted_relationship_name}", controller: options[:controller],
196
- action: 'update_relationship', relationship: link_type.to_s, via: [:put, :patch]
213
+ action: 'update_relationship', relationship: link_type.to_s, via: [:put, :patch]
197
214
  end
198
215
 
199
216
  if methods.include?(:destroy)
200
217
  match "relationships/#{formatted_relationship_name}", controller: options[:controller],
201
- action: 'destroy_relationship', relationship: link_type.to_s, via: [:delete]
218
+ action: 'destroy_relationship', relationship: link_type.to_s, via: [:delete]
202
219
  end
203
220
  end
204
221
  end
@@ -210,6 +227,8 @@ module ActionDispatch
210
227
  relationship_name = relationship.first
211
228
  relationship = source._relationships[relationship_name]
212
229
 
230
+ relationship._routed = true
231
+
213
232
  formatted_relationship_name = format_route(relationship.name)
214
233
 
215
234
  if relationship.polymorphic?
@@ -219,9 +238,10 @@ module ActionDispatch
219
238
  options[:controller] ||= related_resource._type.to_s
220
239
  end
221
240
 
222
- match "#{formatted_relationship_name}", controller: options[:controller],
223
- relationship: relationship.name, source: resource_type_with_module_prefix(source._type),
224
- action: 'get_related_resource', via: [:get]
241
+ match formatted_relationship_name, controller: options[:controller],
242
+ relationship: relationship.name, source: resource_type_with_module_prefix(source._type),
243
+ action: 'get_related_resource', via: [:get],
244
+ as: "related/#{relationship_name}"
225
245
  end
226
246
 
227
247
  def jsonapi_related_resources(*relationship)
@@ -231,13 +251,17 @@ module ActionDispatch
231
251
  relationship_name = relationship.first
232
252
  relationship = source._relationships[relationship_name]
233
253
 
254
+ relationship._routed = true
255
+
234
256
  formatted_relationship_name = format_route(relationship.name)
235
257
  related_resource = JSONAPI::Resource.resource_for(resource_type_with_module_prefix(relationship.class_name.underscore))
236
258
  options[:controller] ||= related_resource._type.to_s
237
259
 
238
- match "#{formatted_relationship_name}", controller: options[:controller],
239
- relationship: relationship.name, source: resource_type_with_module_prefix(source._type),
240
- action: 'get_related_resources', via: [:get]
260
+ match formatted_relationship_name,
261
+ controller: options[:controller],
262
+ relationship: relationship.name, source: resource_type_with_module_prefix(source._type),
263
+ action: 'get_related_resources', via: [:get],
264
+ as: "related/#{relationship_name}"
241
265
  end
242
266
 
243
267
  protected
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.9.0
4
+ version: 0.9.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dan Gebhardt
@@ -9,22 +9,22 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2017-02-14 00:00:00.000000000 Z
12
+ date: 2021-02-04 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  requirements:
18
- - - "~>"
18
+ - - ">="
19
19
  - !ruby/object:Gem::Version
20
- version: '1.5'
20
+ version: '0'
21
21
  type: :development
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
- - - "~>"
25
+ - - ">="
26
26
  - !ruby/object:Gem::Version
27
- version: '1.5'
27
+ version: '0'
28
28
  - !ruby/object:Gem::Dependency
29
29
  name: rake
30
30
  requirement: !ruby/object:Gem::Requirement
@@ -109,6 +109,34 @@ dependencies:
109
109
  - - ">="
110
110
  - !ruby/object:Gem::Version
111
111
  version: '0'
112
+ - !ruby/object:Gem::Dependency
113
+ name: database_cleaner
114
+ requirement: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ type: :development
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ - !ruby/object:Gem::Dependency
127
+ name: memory_profiler
128
+ requirement: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ version: '0'
133
+ type: :development
134
+ prerelease: false
135
+ version_requirements: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ version: '0'
112
140
  - !ruby/object:Gem::Dependency
113
141
  name: activerecord
114
142
  requirement: !ruby/object:Gem::Requirement
@@ -216,8 +244,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
216
244
  - !ruby/object:Gem::Version
217
245
  version: '0'
218
246
  requirements: []
219
- rubyforge_project:
220
- rubygems_version: 2.5.1
247
+ rubygems_version: 3.0.3
221
248
  signing_key:
222
249
  specification_version: 4
223
250
  summary: Easily support JSON API in Rails.