jpie 1.3.1 → 1.5.0
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/Gemfile.lock +1 -1
- data/README.md +5 -3
- data/lib/json_api/routing.rb +8 -1
- data/lib/json_api/serialization/concerns/includes_serialization.rb +52 -12
- data/lib/json_api/serialization/concerns/links_serialization.rb +13 -1
- data/lib/json_api/serialization/concerns/relationships_serialization.rb +5 -1
- data/lib/json_api/serialization/serializer.rb +10 -6
- data/lib/json_api/version.rb +1 -1
- metadata +1 -2
- data/kiln/app/resources/user_message_resource.rb +0 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d6718c74febd247abaa1dd7294fd729209a3e905363e02d8bb88f20e6a8ee92e
|
|
4
|
+
data.tar.gz: 388c8ee9564f191f14e87d0095d15657dd4ccb55c841d26755d8d7916811d0f0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d4188461bf266a55290b2728691e8b052b8f8eeb2ba319949aa0fbb23109dc9175e2c7d29aa53e3768fe794738cd7f5b70e83f624ec0ff72af13051159eb4800
|
|
7
|
+
data.tar.gz: dd193aec85fc8fb12ef21200eca3341411d7c12c0e32f5d2d50562d4fcbefd76ddfc4d08ea36b2c69204c2b579fa2dd9cac18cd2aa4540898f4a9f9543422218
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -238,6 +238,8 @@ Nested includes use dot notation and support arbitrary depth. Related resources
|
|
|
238
238
|
}
|
|
239
239
|
```
|
|
240
240
|
|
|
241
|
+
Only relationships that appear in the `include` path are serialized (and thus loaded). For example, `include=messages` adds messages to `included` but does not serialize each message's `user`, `message_action`, or other relationships, so those associations are not queried. Use `include=messages,messages.user,messages.message_action` (etc.) to include and load nested relationships.
|
|
242
|
+
|
|
241
243
|
## Polymorphic Relationships
|
|
242
244
|
|
|
243
245
|
Polymorphic relationships are accessed through the parent resource's relationship endpoints and includes. Route only the parent resource; the gem automatically handles polymorphic types through the relationship endpoints.
|
|
@@ -1392,7 +1394,7 @@ api.define(
|
|
|
1392
1394
|
},
|
|
1393
1395
|
{
|
|
1394
1396
|
collectionPath: "users",
|
|
1395
|
-
}
|
|
1397
|
+
},
|
|
1396
1398
|
);
|
|
1397
1399
|
|
|
1398
1400
|
// Model with relationships
|
|
@@ -1412,7 +1414,7 @@ api.define(
|
|
|
1412
1414
|
},
|
|
1413
1415
|
{
|
|
1414
1416
|
collectionPath: "posts",
|
|
1415
|
-
}
|
|
1417
|
+
},
|
|
1416
1418
|
);
|
|
1417
1419
|
```
|
|
1418
1420
|
|
|
@@ -1622,7 +1624,7 @@ api.define(
|
|
|
1622
1624
|
},
|
|
1623
1625
|
{
|
|
1624
1626
|
collectionPath: "workstreams",
|
|
1625
|
-
}
|
|
1627
|
+
},
|
|
1626
1628
|
);
|
|
1627
1629
|
|
|
1628
1630
|
// Create with polymorphic relationship
|
data/lib/json_api/routing.rb
CHANGED
|
@@ -65,7 +65,14 @@ module JSONAPI
|
|
|
65
65
|
end
|
|
66
66
|
|
|
67
67
|
def define_explicit_sti_routes(sti_resources, defaults)
|
|
68
|
-
sti_resources.each
|
|
68
|
+
sti_resources.each do |entry|
|
|
69
|
+
case entry
|
|
70
|
+
in Hash
|
|
71
|
+
entry.each { |sub_resource_name, options| jsonapi_resources(sub_resource_name, defaults:, **options) }
|
|
72
|
+
else
|
|
73
|
+
jsonapi_resources(entry, defaults:)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
69
76
|
end
|
|
70
77
|
|
|
71
78
|
def define_auto_sti_routes(resource, resource_name, defaults, namespace = nil)
|
|
@@ -4,13 +4,14 @@ module JSONAPI
|
|
|
4
4
|
module Serialization
|
|
5
5
|
module IncludesSerialization
|
|
6
6
|
def serialize_included(includes, fields = {})
|
|
7
|
-
|
|
7
|
+
all_includes = normalize_include_paths(includes)
|
|
8
|
+
return [] if all_includes.empty?
|
|
8
9
|
|
|
9
10
|
included_records = []
|
|
10
11
|
processed = Set.new
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
serialize_include_path(record, include_path, fields, included_records, processed)
|
|
13
|
+
all_includes.each do |include_path|
|
|
14
|
+
serialize_include_path(record, include_path, fields, included_records, processed, all_includes:)
|
|
14
15
|
end
|
|
15
16
|
|
|
16
17
|
included_records
|
|
@@ -18,7 +19,7 @@ module JSONAPI
|
|
|
18
19
|
|
|
19
20
|
private
|
|
20
21
|
|
|
21
|
-
def serialize_include_path(current_record, include_path, fields, included_records, processed)
|
|
22
|
+
def serialize_include_path(current_record, include_path, fields, included_records, processed, all_includes:)
|
|
22
23
|
path_parts = include_path.split(".")
|
|
23
24
|
association_name = path_parts.first.to_sym
|
|
24
25
|
|
|
@@ -26,8 +27,9 @@ module JSONAPI
|
|
|
26
27
|
|
|
27
28
|
related_array = get_related_records(current_record, association_name)
|
|
28
29
|
related_array.each do |related_record|
|
|
29
|
-
|
|
30
|
-
|
|
30
|
+
parent_context = self.class.active_storage_attachment?(association_name, current_record.class) ? { parent_record: current_record, association_name: } : {}
|
|
31
|
+
serialize_and_process_record(related_record, include_path, all_includes, fields, included_records, processed, **parent_context)
|
|
32
|
+
serialize_nested_path(related_record, path_parts, fields, included_records, processed, all_includes:)
|
|
31
33
|
end
|
|
32
34
|
end
|
|
33
35
|
|
|
@@ -54,7 +56,16 @@ module JSONAPI
|
|
|
54
56
|
related_klass = association.klass
|
|
55
57
|
return [] if related_klass.blank?
|
|
56
58
|
|
|
57
|
-
build_scoped_relation(related_klass, association)
|
|
59
|
+
scope = build_scoped_relation(related_klass, association)
|
|
60
|
+
association.loaded? ? scope_loaded_to_records_scope(association, scope) : scope.to_a
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def scope_loaded_to_records_scope(association, scope)
|
|
64
|
+
loaded_array = association.target.respond_to?(:to_a) ? association.target.to_a : Array(association.target)
|
|
65
|
+
loaded_ids = loaded_array.filter_map(&:id)
|
|
66
|
+
return [] if loaded_ids.empty?
|
|
67
|
+
|
|
68
|
+
scope.where(id: loaded_ids).to_a
|
|
58
69
|
end
|
|
59
70
|
|
|
60
71
|
def build_scoped_relation(related_klass, association)
|
|
@@ -70,12 +81,13 @@ module JSONAPI
|
|
|
70
81
|
[attachment.blob].compact
|
|
71
82
|
end
|
|
72
83
|
|
|
73
|
-
def serialize_and_process_record(related_record, fields, included_records, processed)
|
|
84
|
+
def serialize_and_process_record(related_record, include_path, all_includes, fields, included_records, processed, parent_record: nil, association_name: nil) # rubocop:disable Metrics/ParameterLists
|
|
74
85
|
record_key = build_record_key(related_record)
|
|
75
86
|
return if processed.include?(record_key)
|
|
76
87
|
|
|
77
|
-
|
|
78
|
-
|
|
88
|
+
requested_relationships = include_paths_to_relationship_names(all_includes, include_path)
|
|
89
|
+
serializer = self.class.new(related_record, parent_record:, association_name:)
|
|
90
|
+
included_records << serializer.serialize_record(fields, requested_relationships: requested_relationships)
|
|
79
91
|
processed.add(record_key)
|
|
80
92
|
end
|
|
81
93
|
|
|
@@ -83,11 +95,39 @@ module JSONAPI
|
|
|
83
95
|
"#{related_record.class.name}-#{related_record.id}"
|
|
84
96
|
end
|
|
85
97
|
|
|
86
|
-
def serialize_nested_path(related_record, path_parts, fields, included_records, processed)
|
|
98
|
+
def serialize_nested_path(related_record, path_parts, fields, included_records, processed, all_includes:)
|
|
87
99
|
return unless path_parts.length > 1
|
|
88
100
|
|
|
89
101
|
nested_path = path_parts[1..].join(".")
|
|
90
|
-
serialize_include_path(related_record, nested_path, fields, included_records, processed
|
|
102
|
+
serialize_include_path(related_record, nested_path, fields, included_records, processed,
|
|
103
|
+
all_includes: all_includes,)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def normalize_include_paths(include_param)
|
|
107
|
+
case include_param
|
|
108
|
+
when Array
|
|
109
|
+
include_param.flat_map { |s| s.to_s.split(",").map(&:strip) }.uniq
|
|
110
|
+
when String
|
|
111
|
+
include_param.split(",").map(&:strip)
|
|
112
|
+
else
|
|
113
|
+
[]
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def include_paths_to_relationship_names(include_paths, path_prefix)
|
|
118
|
+
return [] if include_paths.blank?
|
|
119
|
+
|
|
120
|
+
prefix = path_prefix.present? ? "#{path_prefix}." : ""
|
|
121
|
+
include_paths.filter_map do |p|
|
|
122
|
+
path = p.to_s
|
|
123
|
+
next unless path == path_prefix || path.start_with?(prefix)
|
|
124
|
+
|
|
125
|
+
segments = path.split(".")
|
|
126
|
+
prefix_segments = path_prefix.split(".")
|
|
127
|
+
next if segments.length <= prefix_segments.length
|
|
128
|
+
|
|
129
|
+
segments[prefix_segments.length].to_sym
|
|
130
|
+
end.uniq
|
|
91
131
|
end
|
|
92
132
|
end
|
|
93
133
|
end
|
|
@@ -16,11 +16,23 @@ module JSONAPI
|
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
def add_active_storage_download_link(links)
|
|
19
|
-
links[:download] =
|
|
19
|
+
links[:download] = variant_or_blob_path || fallback_blob_path
|
|
20
20
|
rescue StandardError
|
|
21
21
|
links[:download] = fallback_blob_path
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
+
def variant_or_blob_path
|
|
25
|
+
return rails_blob_path unless parent_record && association_name && record.content_type&.start_with?("image/")
|
|
26
|
+
|
|
27
|
+
parent_definition = ResourceLoader.find_for_model(parent_record.class)
|
|
28
|
+
rel_def = RelationshipHelpers.find_relationship_definition(parent_definition, association_name)
|
|
29
|
+
variant_opts = rel_def&.dig(:options, :variant)
|
|
30
|
+
return rails_blob_path unless variant_opts.present?
|
|
31
|
+
|
|
32
|
+
representation = record.representation(**variant_opts.symbolize_keys)
|
|
33
|
+
Rails.application.routes.url_helpers.rails_representation_path(representation, only_path: true)
|
|
34
|
+
end
|
|
35
|
+
|
|
24
36
|
def rails_blob_path
|
|
25
37
|
Rails.application.routes.url_helpers.rails_blob_path(record, only_path: true)
|
|
26
38
|
end
|
|
@@ -3,9 +3,13 @@
|
|
|
3
3
|
module JSONAPI
|
|
4
4
|
module Serialization
|
|
5
5
|
module RelationshipsSerialization
|
|
6
|
-
def serialize_relationships
|
|
6
|
+
def serialize_relationships(requested_relationship_names = nil)
|
|
7
7
|
relationships = {}
|
|
8
8
|
relationship_definitions = definition.relationship_definitions
|
|
9
|
+
if requested_relationship_names
|
|
10
|
+
requested_set = requested_relationship_names.map(&:to_sym)
|
|
11
|
+
relationship_definitions = relationship_definitions.select { |r| requested_set.include?(r[:name]) }
|
|
12
|
+
end
|
|
9
13
|
|
|
10
14
|
relationship_definitions.each do |rel_def|
|
|
11
15
|
serialize_relationship(rel_def, relationships)
|
|
@@ -33,28 +33,32 @@ module JSONAPI
|
|
|
33
33
|
@jsonapi_object = nil
|
|
34
34
|
end
|
|
35
35
|
|
|
36
|
-
def initialize(record, definition: nil, base_definition: nil)
|
|
36
|
+
def initialize(record, definition: nil, base_definition: nil, parent_record: nil, association_name: nil)
|
|
37
37
|
@record = record
|
|
38
38
|
@definition = definition || ResourceLoader.find_for_model(record.class)
|
|
39
39
|
@base_definition = base_definition
|
|
40
|
+
@parent_record = parent_record
|
|
41
|
+
@association_name = association_name
|
|
40
42
|
@sti_subclass = nil
|
|
41
43
|
end
|
|
42
44
|
|
|
43
45
|
def to_hash(include: [], fields: {}, document_meta: nil)
|
|
46
|
+
include_paths = normalize_include_paths(include)
|
|
47
|
+
top_level_relationships = include_paths_to_relationship_names(include_paths, "")
|
|
44
48
|
{
|
|
45
49
|
jsonapi: jsonapi_object,
|
|
46
|
-
data: serialize_record(fields),
|
|
47
|
-
included: serialize_included(
|
|
50
|
+
data: serialize_record(fields, requested_relationships: top_level_relationships),
|
|
51
|
+
included: serialize_included(include_paths, fields),
|
|
48
52
|
meta: document_meta,
|
|
49
53
|
}.compact
|
|
50
54
|
end
|
|
51
55
|
|
|
52
|
-
def serialize_record(fields = {})
|
|
56
|
+
def serialize_record(fields = {}, requested_relationships: nil)
|
|
53
57
|
{
|
|
54
58
|
type: record_type,
|
|
55
59
|
id: record_id,
|
|
56
60
|
attributes: serialize_attributes(fields),
|
|
57
|
-
relationships: serialize_relationships,
|
|
61
|
+
relationships: serialize_relationships(requested_relationships),
|
|
58
62
|
links: serialize_links,
|
|
59
63
|
meta: record_meta,
|
|
60
64
|
}.compact
|
|
@@ -62,7 +66,7 @@ module JSONAPI
|
|
|
62
66
|
|
|
63
67
|
private
|
|
64
68
|
|
|
65
|
-
attr_reader :record, :definition
|
|
69
|
+
attr_reader :record, :definition, :parent_record, :association_name
|
|
66
70
|
|
|
67
71
|
def base_definition
|
|
68
72
|
@base_definition ||= definition
|
data/lib/json_api/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: jpie
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Emil Kampp
|
|
@@ -70,7 +70,6 @@ files:
|
|
|
70
70
|
- bin/console
|
|
71
71
|
- bin/setup
|
|
72
72
|
- jpie.gemspec
|
|
73
|
-
- kiln/app/resources/user_message_resource.rb
|
|
74
73
|
- lib/jpie.rb
|
|
75
74
|
- lib/json_api.rb
|
|
76
75
|
- lib/json_api/active_storage/deserialization.rb
|