jsonapi-resources 0.9.11 → 0.10.7
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/LICENSE.txt +1 -1
- data/README.md +34 -11
- data/lib/bug_report_templates/rails_5_latest.rb +125 -0
- data/lib/bug_report_templates/rails_5_master.rb +140 -0
- data/lib/jsonapi/active_relation/adapters/join_left_active_record_adapter.rb +27 -0
- data/lib/jsonapi/active_relation/join_manager.rb +303 -0
- data/lib/jsonapi/active_relation_resource.rb +884 -0
- data/lib/jsonapi/acts_as_resource_controller.rb +122 -106
- data/lib/jsonapi/basic_resource.rb +1162 -0
- data/lib/jsonapi/cached_response_fragment.rb +127 -0
- data/lib/jsonapi/compiled_json.rb +11 -1
- data/lib/jsonapi/configuration.rb +57 -8
- data/lib/jsonapi/error.rb +27 -0
- data/lib/jsonapi/error_codes.rb +2 -0
- data/lib/jsonapi/exceptions.rb +63 -40
- data/lib/jsonapi/formatter.rb +3 -3
- data/lib/jsonapi/include_directives.rb +18 -75
- data/lib/jsonapi/link_builder.rb +16 -19
- data/lib/jsonapi/operation.rb +16 -5
- data/lib/jsonapi/operation_result.rb +73 -15
- data/lib/jsonapi/paginator.rb +17 -0
- data/lib/jsonapi/path.rb +43 -0
- data/lib/jsonapi/path_segment.rb +76 -0
- data/lib/jsonapi/processor.rb +246 -111
- data/lib/jsonapi/relationship.rb +117 -18
- data/lib/jsonapi/request_parser.rb +383 -396
- data/lib/jsonapi/resource.rb +3 -1376
- data/lib/jsonapi/resource_controller_metal.rb +5 -2
- data/lib/jsonapi/resource_fragment.rb +47 -0
- data/lib/jsonapi/resource_id_tree.rb +112 -0
- data/lib/jsonapi/resource_identity.rb +42 -0
- data/lib/jsonapi/resource_serializer.rb +124 -286
- data/lib/jsonapi/resource_set.rb +176 -0
- data/lib/jsonapi/resources/railtie.rb +9 -0
- data/lib/jsonapi/resources/version.rb +1 -1
- data/lib/jsonapi/response_document.rb +104 -87
- data/lib/jsonapi/routing_ext.rb +19 -21
- data/lib/jsonapi-resources.rb +20 -4
- data/lib/tasks/check_upgrade.rake +52 -0
- metadata +36 -33
- data/lib/jsonapi/cached_resource_fragment.rb +0 -127
- data/lib/jsonapi/operation_dispatcher.rb +0 -88
- data/lib/jsonapi/operation_results.rb +0 -35
- data/lib/jsonapi/relationship_builder.rb +0 -167
@@ -0,0 +1,176 @@
|
|
1
|
+
module JSONAPI
|
2
|
+
# Contains a hash of resource types which contain a hash of resources, relationships and primary status keyed by
|
3
|
+
# resource id.
|
4
|
+
class ResourceSet
|
5
|
+
|
6
|
+
attr_reader :resource_klasses, :populated
|
7
|
+
|
8
|
+
def initialize(resource_id_tree = nil)
|
9
|
+
@populated = false
|
10
|
+
@resource_klasses = resource_id_tree.nil? ? {} : flatten_resource_id_tree(resource_id_tree)
|
11
|
+
end
|
12
|
+
|
13
|
+
def populate!(serializer, context, find_options)
|
14
|
+
# For each resource klass we want to generate the caching key
|
15
|
+
|
16
|
+
# Hash for collecting types and ids
|
17
|
+
# @type [Hash<Class<Resource>, Id[]]]
|
18
|
+
missed_resource_ids = {}
|
19
|
+
|
20
|
+
# Array for collecting CachedResponseFragment::Lookups
|
21
|
+
# @type [Lookup[]]
|
22
|
+
lookups = []
|
23
|
+
|
24
|
+
|
25
|
+
# Step One collect all of the lookups for the cache, or keys that don't require cache access
|
26
|
+
@resource_klasses.each_key do |resource_klass|
|
27
|
+
|
28
|
+
serializer_config_key = serializer.config_key(resource_klass).gsub("/", "_")
|
29
|
+
context_json = resource_klass.attribute_caching_context(context).to_json
|
30
|
+
context_b64 = JSONAPI.configuration.resource_cache_digest_function.call(context_json)
|
31
|
+
context_key = "ATTR-CTX-#{context_b64.gsub("/", "_")}"
|
32
|
+
|
33
|
+
if resource_klass.caching?
|
34
|
+
cache_ids = @resource_klasses[resource_klass].map do |(k, v)|
|
35
|
+
# Store the hashcode of the cache_field to avoid storing objects and to ensure precision isn't lost
|
36
|
+
# on timestamp types (i.e. string conversions dropping milliseconds)
|
37
|
+
[k, resource_klass.hash_cache_field(v[:cache_id])]
|
38
|
+
end
|
39
|
+
|
40
|
+
lookups.push(
|
41
|
+
CachedResponseFragment::Lookup.new(
|
42
|
+
resource_klass,
|
43
|
+
serializer_config_key,
|
44
|
+
context,
|
45
|
+
context_key,
|
46
|
+
cache_ids
|
47
|
+
)
|
48
|
+
)
|
49
|
+
else
|
50
|
+
missed_resource_ids[resource_klass] = @resource_klasses[resource_klass].keys
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
if lookups.any?
|
55
|
+
raise "You've declared some Resources as caching without providing a caching store" if JSONAPI.configuration.resource_cache.nil?
|
56
|
+
|
57
|
+
# Step Two execute the cache lookup
|
58
|
+
found_resources = CachedResponseFragment.lookup(lookups, context)
|
59
|
+
else
|
60
|
+
found_resources = {}
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
# Step Three collect the results and collect hit/miss stats
|
65
|
+
stats = {}
|
66
|
+
found_resources.each do |resource_klass, resources|
|
67
|
+
resources.each do |id, cached_resource|
|
68
|
+
stats[resource_klass] ||= {}
|
69
|
+
|
70
|
+
if cached_resource.nil?
|
71
|
+
stats[resource_klass][:misses] ||= 0
|
72
|
+
stats[resource_klass][:misses] += 1
|
73
|
+
|
74
|
+
# Collect misses
|
75
|
+
missed_resource_ids[resource_klass] ||= []
|
76
|
+
missed_resource_ids[resource_klass].push(id)
|
77
|
+
else
|
78
|
+
stats[resource_klass][:hits] ||= 0
|
79
|
+
stats[resource_klass][:hits] += 1
|
80
|
+
|
81
|
+
register_resource(resource_klass, cached_resource)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
report_stats(stats)
|
87
|
+
|
88
|
+
writes = []
|
89
|
+
|
90
|
+
# Step Four find any of the missing resources and join them into the result
|
91
|
+
missed_resource_ids.each_pair do |resource_klass, ids|
|
92
|
+
find_opts = {context: context, fields: find_options[:fields]}
|
93
|
+
found_resources = resource_klass.find_to_populate_by_keys(ids, find_opts)
|
94
|
+
|
95
|
+
found_resources.each do |resource|
|
96
|
+
relationship_data = @resource_klasses[resource_klass][resource.id][:relationships]
|
97
|
+
|
98
|
+
if resource_klass.caching?
|
99
|
+
|
100
|
+
serializer_config_key = serializer.config_key(resource_klass).gsub("/", "_")
|
101
|
+
context_json = resource_klass.attribute_caching_context(context).to_json
|
102
|
+
context_b64 = JSONAPI.configuration.resource_cache_digest_function.call(context_json)
|
103
|
+
context_key = "ATTR-CTX-#{context_b64.gsub("/", "_")}"
|
104
|
+
|
105
|
+
writes.push(CachedResponseFragment::Write.new(
|
106
|
+
resource_klass,
|
107
|
+
resource,
|
108
|
+
serializer,
|
109
|
+
serializer_config_key,
|
110
|
+
context,
|
111
|
+
context_key,
|
112
|
+
relationship_data
|
113
|
+
))
|
114
|
+
end
|
115
|
+
|
116
|
+
register_resource(resource_klass, resource)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
# Step Five conditionally write to the cache
|
121
|
+
CachedResponseFragment.write(writes) unless JSONAPI.configuration.resource_cache.nil?
|
122
|
+
|
123
|
+
mark_populated!
|
124
|
+
self
|
125
|
+
end
|
126
|
+
|
127
|
+
def mark_populated!
|
128
|
+
@populated = true
|
129
|
+
end
|
130
|
+
|
131
|
+
def register_resource(resource_klass, resource, primary = false)
|
132
|
+
@resource_klasses[resource_klass] ||= {}
|
133
|
+
@resource_klasses[resource_klass][resource.id] ||= {primary: resource.try(:primary) || primary, relationships: {}}
|
134
|
+
@resource_klasses[resource_klass][resource.id][:resource] = resource
|
135
|
+
end
|
136
|
+
|
137
|
+
private
|
138
|
+
|
139
|
+
def report_stats(stats)
|
140
|
+
return unless JSONAPI.configuration.resource_cache_usage_report_function || JSONAPI.configuration.resource_cache.nil?
|
141
|
+
|
142
|
+
stats.each_pair do |resource_klass, stat|
|
143
|
+
JSONAPI.configuration.resource_cache_usage_report_function.call(
|
144
|
+
resource_klass.name,
|
145
|
+
stat[:hits] || 0,
|
146
|
+
stat[:misses] || 0
|
147
|
+
)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def flatten_resource_id_tree(resource_id_tree, flattened_tree = {})
|
152
|
+
resource_id_tree.fragments.each_pair do |resource_rid, fragment|
|
153
|
+
|
154
|
+
resource_klass = resource_rid.resource_klass
|
155
|
+
id = resource_rid.id
|
156
|
+
|
157
|
+
flattened_tree[resource_klass] ||= {}
|
158
|
+
|
159
|
+
flattened_tree[resource_klass][id] ||= {primary: fragment.primary, relationships: {}}
|
160
|
+
flattened_tree[resource_klass][id][:cache_id] ||= fragment.cache
|
161
|
+
|
162
|
+
fragment.related.try(:each_pair) do |relationship_name, related_rids|
|
163
|
+
flattened_tree[resource_klass][id][:relationships][relationship_name] ||= Set.new
|
164
|
+
flattened_tree[resource_klass][id][:relationships][relationship_name].merge(related_rids)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
related_resource_id_trees = resource_id_tree.related_resource_id_trees
|
169
|
+
related_resource_id_trees.try(:each_value) do |related_resource_id_tree|
|
170
|
+
flatten_resource_id_tree(related_resource_id_tree, flattened_tree)
|
171
|
+
end
|
172
|
+
|
173
|
+
flattened_tree
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
@@ -1,86 +1,138 @@
|
|
1
1
|
module JSONAPI
|
2
2
|
class ResponseDocument
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
attr_reader :serialized_results
|
4
|
+
|
5
|
+
def initialize(options = {})
|
6
|
+
@serialized_results = []
|
7
|
+
@result_codes = []
|
8
|
+
@error_results = []
|
9
|
+
@global_errors = []
|
10
|
+
|
6
11
|
@options = options
|
7
12
|
|
13
|
+
@top_level_meta = @options.fetch(:base_meta, {})
|
14
|
+
@top_level_links = @options.fetch(:base_links, {})
|
15
|
+
|
8
16
|
@key_formatter = @options.fetch(:key_formatter, JSONAPI.configuration.key_formatter)
|
9
17
|
end
|
10
18
|
|
11
|
-
def
|
12
|
-
|
19
|
+
def has_errors?
|
20
|
+
@error_results.length > 0 || @global_errors.length > 0
|
21
|
+
end
|
13
22
|
|
14
|
-
|
15
|
-
|
23
|
+
def add_result(result, operation)
|
24
|
+
if result.is_a?(JSONAPI::ErrorsOperationResult)
|
25
|
+
# Clear any serialized results
|
26
|
+
@serialized_results = []
|
16
27
|
|
17
|
-
|
18
|
-
|
28
|
+
# In JSONAPI v1 we only have one operation so all errors can be kept together
|
29
|
+
result.errors.each do |error|
|
30
|
+
add_global_error(error)
|
31
|
+
end
|
32
|
+
else
|
33
|
+
@serialized_results.push result.to_hash(operation.options[:serializer])
|
34
|
+
@result_codes.push result.code.to_i
|
35
|
+
update_links(operation.options[:serializer], result)
|
36
|
+
update_meta(result)
|
37
|
+
end
|
38
|
+
end
|
19
39
|
|
20
|
-
|
40
|
+
def add_global_error(error)
|
41
|
+
@global_errors.push error
|
21
42
|
end
|
22
43
|
|
23
|
-
def
|
24
|
-
if
|
25
|
-
@
|
44
|
+
def contents
|
45
|
+
if has_errors?
|
46
|
+
return { 'errors' => @global_errors }
|
26
47
|
else
|
27
|
-
@
|
48
|
+
hash = @serialized_results[0]
|
49
|
+
meta = top_level_meta
|
50
|
+
hash.merge!('meta' => meta) unless meta.empty?
|
51
|
+
|
52
|
+
links = top_level_links
|
53
|
+
hash.merge!('links' => links) unless links.empty?
|
54
|
+
|
55
|
+
return hash
|
28
56
|
end
|
29
57
|
end
|
30
58
|
|
31
|
-
|
59
|
+
def status
|
60
|
+
status_codes = if has_errors?
|
61
|
+
@global_errors.collect do |error|
|
62
|
+
error.status.to_i
|
63
|
+
end
|
64
|
+
else
|
65
|
+
@result_codes
|
66
|
+
end
|
67
|
+
|
68
|
+
# Count the unique status codes
|
69
|
+
counts = status_codes.each_with_object(Hash.new(0)) { |code, counts| counts[code] += 1 }
|
70
|
+
|
71
|
+
# if there is only one status code we can return that
|
72
|
+
return counts.keys[0].to_i if counts.length == 1
|
73
|
+
|
74
|
+
# :nocov: not currently used
|
75
|
+
|
76
|
+
# if there are many we should return the highest general code, 200, 400, 500 etc.
|
77
|
+
max_status = 0
|
78
|
+
status_codes.each do |status|
|
79
|
+
code = status.to_i
|
80
|
+
max_status = code if max_status < code
|
81
|
+
end
|
82
|
+
return (max_status / 100).floor * 100
|
83
|
+
# :nocov:
|
84
|
+
end
|
32
85
|
|
33
|
-
|
34
|
-
# and the result of each operation. The keys are then formatted.
|
35
|
-
def top_level_meta
|
36
|
-
meta = @options.fetch(:base_meta, {})
|
86
|
+
private
|
37
87
|
|
38
|
-
|
88
|
+
def update_meta(result)
|
89
|
+
@top_level_meta.merge!(result.meta)
|
39
90
|
|
40
|
-
|
41
|
-
|
91
|
+
if JSONAPI.configuration.top_level_meta_include_record_count && result.respond_to?(:record_count)
|
92
|
+
@top_level_meta[JSONAPI.configuration.top_level_meta_record_count_key] = result.record_count
|
93
|
+
end
|
42
94
|
|
43
|
-
|
44
|
-
|
45
|
-
|
95
|
+
if JSONAPI.configuration.top_level_meta_include_page_count && result.respond_to?(:page_count)
|
96
|
+
@top_level_meta[JSONAPI.configuration.top_level_meta_page_count_key] = result.page_count
|
97
|
+
end
|
46
98
|
|
47
|
-
|
48
|
-
|
99
|
+
if result.warnings.any?
|
100
|
+
@top_level_meta[:warnings] = result.warnings.collect do |warning|
|
101
|
+
warning.to_hash
|
49
102
|
end
|
50
103
|
end
|
104
|
+
end
|
51
105
|
|
52
|
-
|
106
|
+
def top_level_meta
|
107
|
+
@top_level_meta.as_json.deep_transform_keys { |key| @key_formatter.format(key) }
|
53
108
|
end
|
54
109
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
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))
|
76
|
-
end
|
110
|
+
def update_links(serializer, result)
|
111
|
+
@top_level_links.merge!(result.links)
|
112
|
+
|
113
|
+
# Build pagination links
|
114
|
+
if result.is_a?(JSONAPI::ResourceSetOperationResult) ||
|
115
|
+
result.is_a?(JSONAPI::ResourcesSetOperationResult) ||
|
116
|
+
result.is_a?(JSONAPI::RelatedResourcesSetOperationResult)
|
117
|
+
|
118
|
+
result.pagination_params.each_pair do |link_name, params|
|
119
|
+
if result.is_a?(JSONAPI::RelatedResourcesSetOperationResult)
|
120
|
+
relationship = result.source_resource.class._relationships[result._type.to_sym]
|
121
|
+
unless relationship.exclude_link?(link_name)
|
122
|
+
link = serializer.link_builder.relationships_related_link(result.source_resource, relationship, query_params(params))
|
123
|
+
end
|
124
|
+
else
|
125
|
+
unless serializer.link_builder.primary_resource_klass.exclude_link?(link_name)
|
126
|
+
link = serializer.link_builder.query_link(query_params(params))
|
77
127
|
end
|
78
|
-
links[link_name] = link unless link.blank?
|
79
128
|
end
|
129
|
+
@top_level_links[link_name] = link unless link.blank?
|
80
130
|
end
|
81
131
|
end
|
132
|
+
end
|
82
133
|
|
83
|
-
|
134
|
+
def top_level_links
|
135
|
+
@top_level_links.deep_transform_keys { |key| @key_formatter.format(key) }
|
84
136
|
end
|
85
137
|
|
86
138
|
def query_params(params)
|
@@ -101,40 +153,5 @@ module JSONAPI
|
|
101
153
|
|
102
154
|
query_params
|
103
155
|
end
|
104
|
-
|
105
|
-
def results_to_hash
|
106
|
-
if @operation_results.has_errors?
|
107
|
-
{ errors: @operation_results.all_errors }
|
108
|
-
else
|
109
|
-
if @operation_results.results.length == 1
|
110
|
-
result = @operation_results.results[0]
|
111
|
-
|
112
|
-
case result
|
113
|
-
when JSONAPI::ResourceOperationResult
|
114
|
-
@serializer.serialize_to_hash(result.resource)
|
115
|
-
when JSONAPI::ResourcesOperationResult
|
116
|
-
@serializer.serialize_to_hash(result.resources)
|
117
|
-
when JSONAPI::RelationshipOperationResult
|
118
|
-
@serializer.serialize_to_relationship_hash(result.parent_resource,
|
119
|
-
result.relationship)
|
120
|
-
when JSONAPI::OperationResult
|
121
|
-
{}
|
122
|
-
end
|
123
|
-
|
124
|
-
elsif @operation_results.results.length > 1
|
125
|
-
resources = []
|
126
|
-
@operation_results.results.each do |result|
|
127
|
-
case result
|
128
|
-
when JSONAPI::ResourceOperationResult
|
129
|
-
resources.push(result.resource)
|
130
|
-
when JSONAPI::ResourcesOperationResult
|
131
|
-
resources.concat(result.resources)
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
@serializer.serialize_to_hash(resources)
|
136
|
-
end
|
137
|
-
end
|
138
|
-
end
|
139
156
|
end
|
140
157
|
end
|
data/lib/jsonapi/routing_ext.rb
CHANGED
@@ -18,7 +18,7 @@ module ActionDispatch
|
|
18
18
|
|
19
19
|
def jsonapi_resource(*resources, &_block)
|
20
20
|
@resource_type = resources.first
|
21
|
-
res = JSONAPI::Resource.
|
21
|
+
res = JSONAPI::Resource.resource_klass_for(resource_type_with_module_prefix(@resource_type))
|
22
22
|
|
23
23
|
res._routed = true
|
24
24
|
|
@@ -39,8 +39,8 @@ module ActionDispatch
|
|
39
39
|
end
|
40
40
|
|
41
41
|
if res._immutable
|
42
|
-
options[:except] << :create
|
43
|
-
options[:except] << :update
|
42
|
+
options[:except] << :create unless options[:except].include?(:create) || options[:except].include?('create')
|
43
|
+
options[:except] << :update unless options[:except].include?(:update) || options[:except].include?('update')
|
44
44
|
options[:except] << :destroy unless options[:except].include?(:destroy) || options[:except].include?('destroy')
|
45
45
|
end
|
46
46
|
|
@@ -70,7 +70,7 @@ module ActionDispatch
|
|
70
70
|
end
|
71
71
|
|
72
72
|
def jsonapi_relationships(options = {})
|
73
|
-
res = JSONAPI::Resource.
|
73
|
+
res = JSONAPI::Resource.resource_klass_for(resource_type_with_module_prefix(@resource_type))
|
74
74
|
res._relationships.each do |relationship_name, relationship|
|
75
75
|
if relationship.is_a?(JSONAPI::Relationship::ToMany)
|
76
76
|
jsonapi_links(relationship_name, options)
|
@@ -84,7 +84,7 @@ module ActionDispatch
|
|
84
84
|
|
85
85
|
def jsonapi_resources(*resources, &_block)
|
86
86
|
@resource_type = resources.first
|
87
|
-
res = JSONAPI::Resource.
|
87
|
+
res = JSONAPI::Resource.resource_klass_for(resource_type_with_module_prefix(@resource_type))
|
88
88
|
|
89
89
|
res._routed = true
|
90
90
|
|
@@ -114,8 +114,8 @@ module ActionDispatch
|
|
114
114
|
end
|
115
115
|
|
116
116
|
if res._immutable
|
117
|
-
options[:except] << :create
|
118
|
-
options[:except] << :update
|
117
|
+
options[:except] << :create unless options[:except].include?(:create) || options[:except].include?('create')
|
118
|
+
options[:except] << :update unless options[:except].include?(:update) || options[:except].include?('update')
|
119
119
|
options[:except] << :destroy unless options[:except].include?(:destroy) || options[:except].include?('destroy')
|
120
120
|
end
|
121
121
|
|
@@ -159,28 +159,25 @@ module ActionDispatch
|
|
159
159
|
formatted_relationship_name = format_route(link_type)
|
160
160
|
options = links.extract_options!.dup
|
161
161
|
|
162
|
-
res = JSONAPI::Resource.
|
162
|
+
res = JSONAPI::Resource.resource_klass_for(resource_type_with_module_prefix)
|
163
163
|
options[:controller] ||= res._type.to_s
|
164
164
|
|
165
165
|
methods = links_methods(options)
|
166
166
|
|
167
167
|
if methods.include?(:show)
|
168
|
-
match "relationships/#{formatted_relationship_name}",
|
169
|
-
controller: options[:controller],
|
168
|
+
match "relationships/#{formatted_relationship_name}", controller: options[:controller],
|
170
169
|
action: 'show_relationship', relationship: link_type.to_s, via: [:get],
|
171
170
|
as: "relationships/#{link_type}"
|
172
171
|
end
|
173
172
|
|
174
173
|
if res.mutable?
|
175
174
|
if methods.include?(:update)
|
176
|
-
match "relationships/#{formatted_relationship_name}",
|
177
|
-
controller: options[:controller],
|
175
|
+
match "relationships/#{formatted_relationship_name}", controller: options[:controller],
|
178
176
|
action: 'update_relationship', relationship: link_type.to_s, via: [:put, :patch]
|
179
177
|
end
|
180
178
|
|
181
179
|
if methods.include?(:destroy)
|
182
|
-
match "relationships/#{formatted_relationship_name}",
|
183
|
-
controller: options[:controller],
|
180
|
+
match "relationships/#{formatted_relationship_name}", controller: options[:controller],
|
184
181
|
action: 'destroy_relationship', relationship: link_type.to_s, via: [:delete]
|
185
182
|
end
|
186
183
|
end
|
@@ -191,7 +188,7 @@ module ActionDispatch
|
|
191
188
|
formatted_relationship_name = format_route(link_type)
|
192
189
|
options = links.extract_options!.dup
|
193
190
|
|
194
|
-
res = JSONAPI::Resource.
|
191
|
+
res = JSONAPI::Resource.resource_klass_for(resource_type_with_module_prefix)
|
195
192
|
options[:controller] ||= res._type.to_s
|
196
193
|
|
197
194
|
methods = links_methods(options)
|
@@ -221,7 +218,7 @@ module ActionDispatch
|
|
221
218
|
end
|
222
219
|
|
223
220
|
def jsonapi_related_resource(*relationship)
|
224
|
-
source = JSONAPI::Resource.
|
221
|
+
source = JSONAPI::Resource.resource_klass_for(resource_type_with_module_prefix)
|
225
222
|
options = relationship.extract_options!.dup
|
226
223
|
|
227
224
|
relationship_name = relationship.first
|
@@ -234,18 +231,18 @@ module ActionDispatch
|
|
234
231
|
if relationship.polymorphic?
|
235
232
|
options[:controller] ||= relationship.class_name.underscore.pluralize
|
236
233
|
else
|
237
|
-
related_resource = JSONAPI::Resource.
|
234
|
+
related_resource = JSONAPI::Resource.resource_klass_for(resource_type_with_module_prefix(relationship.class_name.underscore.pluralize))
|
238
235
|
options[:controller] ||= related_resource._type.to_s
|
239
236
|
end
|
240
237
|
|
241
238
|
match formatted_relationship_name, controller: options[:controller],
|
242
239
|
relationship: relationship.name, source: resource_type_with_module_prefix(source._type),
|
243
|
-
action: '
|
240
|
+
action: 'show_related_resource', via: [:get],
|
244
241
|
as: "related/#{relationship_name}"
|
245
242
|
end
|
246
243
|
|
247
244
|
def jsonapi_related_resources(*relationship)
|
248
|
-
source = JSONAPI::Resource.
|
245
|
+
source = JSONAPI::Resource.resource_klass_for(resource_type_with_module_prefix)
|
249
246
|
options = relationship.extract_options!.dup
|
250
247
|
|
251
248
|
relationship_name = relationship.first
|
@@ -254,13 +251,13 @@ module ActionDispatch
|
|
254
251
|
relationship._routed = true
|
255
252
|
|
256
253
|
formatted_relationship_name = format_route(relationship.name)
|
257
|
-
related_resource = JSONAPI::Resource.
|
254
|
+
related_resource = JSONAPI::Resource.resource_klass_for(resource_type_with_module_prefix(relationship.class_name.underscore))
|
258
255
|
options[:controller] ||= related_resource._type.to_s
|
259
256
|
|
260
257
|
match formatted_relationship_name,
|
261
258
|
controller: options[:controller],
|
262
259
|
relationship: relationship.name, source: resource_type_with_module_prefix(source._type),
|
263
|
-
action: '
|
260
|
+
action: 'index_related_resources', via: [:get],
|
264
261
|
as: "related/#{relationship_name}"
|
265
262
|
end
|
266
263
|
|
@@ -274,6 +271,7 @@ module ActionDispatch
|
|
274
271
|
@scope = @scope.parent
|
275
272
|
end
|
276
273
|
# :nocov:
|
274
|
+
|
277
275
|
private
|
278
276
|
|
279
277
|
def resource_type_with_module_prefix(resource = nil)
|
data/lib/jsonapi-resources.rb
CHANGED
@@ -1,10 +1,19 @@
|
|
1
|
+
require 'jsonapi/resources/railtie'
|
1
2
|
require 'jsonapi/naive_cache'
|
2
3
|
require 'jsonapi/compiled_json'
|
4
|
+
require 'jsonapi/basic_resource'
|
5
|
+
require 'jsonapi/active_relation_resource'
|
3
6
|
require 'jsonapi/resource'
|
4
|
-
require 'jsonapi/
|
7
|
+
require 'jsonapi/cached_response_fragment'
|
5
8
|
require 'jsonapi/response_document'
|
6
9
|
require 'jsonapi/acts_as_resource_controller'
|
7
|
-
|
10
|
+
if Rails::VERSION::MAJOR >= 6
|
11
|
+
ActiveSupport.on_load(:action_controller_base) do
|
12
|
+
require 'jsonapi/resource_controller'
|
13
|
+
end
|
14
|
+
else
|
15
|
+
require 'jsonapi/resource_controller'
|
16
|
+
end
|
8
17
|
require 'jsonapi/resource_controller_metal'
|
9
18
|
require 'jsonapi/resources/version'
|
10
19
|
require 'jsonapi/configuration'
|
@@ -17,11 +26,18 @@ require 'jsonapi/exceptions'
|
|
17
26
|
require 'jsonapi/error'
|
18
27
|
require 'jsonapi/error_codes'
|
19
28
|
require 'jsonapi/request_parser'
|
20
|
-
require 'jsonapi/operation_dispatcher'
|
21
29
|
require 'jsonapi/processor'
|
22
30
|
require 'jsonapi/relationship'
|
23
31
|
require 'jsonapi/include_directives'
|
32
|
+
require 'jsonapi/operation'
|
24
33
|
require 'jsonapi/operation_result'
|
25
|
-
require 'jsonapi/operation_results'
|
26
34
|
require 'jsonapi/callbacks'
|
27
35
|
require 'jsonapi/link_builder'
|
36
|
+
require 'jsonapi/active_relation/adapters/join_left_active_record_adapter'
|
37
|
+
require 'jsonapi/active_relation/join_manager'
|
38
|
+
require 'jsonapi/resource_identity'
|
39
|
+
require 'jsonapi/resource_fragment'
|
40
|
+
require 'jsonapi/resource_id_tree'
|
41
|
+
require 'jsonapi/resource_set'
|
42
|
+
require 'jsonapi/path'
|
43
|
+
require 'jsonapi/path_segment'
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'jsonapi-resources'
|
3
|
+
|
4
|
+
namespace :jsonapi do
|
5
|
+
namespace :resources do
|
6
|
+
desc 'Checks application for orphaned overrides'
|
7
|
+
task :check_upgrade => :environment do
|
8
|
+
Rails.application.eager_load!
|
9
|
+
|
10
|
+
resource_klasses = ObjectSpace.each_object(Class).select { |klass| klass < JSONAPI::Resource}
|
11
|
+
|
12
|
+
puts "Checking #{resource_klasses.count} resources"
|
13
|
+
|
14
|
+
issues_found = 0
|
15
|
+
|
16
|
+
klasses_with_deprecated = resource_klasses.select { |klass| klass.methods.include?(:find_records) }
|
17
|
+
unless klasses_with_deprecated.empty?
|
18
|
+
puts " Found the following resources the still implement `find_records`:"
|
19
|
+
klasses_with_deprecated.each { |klass| puts " #{klass}"}
|
20
|
+
puts " The `find_records` method is no longer called by JR. Please review and ensure your functionality is ported over."
|
21
|
+
|
22
|
+
issues_found = issues_found + klasses_with_deprecated.length
|
23
|
+
end
|
24
|
+
|
25
|
+
klasses_with_deprecated = resource_klasses.select { |klass| klass.methods.include?(:records_for) }
|
26
|
+
unless klasses_with_deprecated.empty?
|
27
|
+
puts " Found the following resources the still implement `records_for`:"
|
28
|
+
klasses_with_deprecated.each { |klass| puts " #{klass}"}
|
29
|
+
puts " The `records_for` method is no longer called by JR. Please review and ensure your functionality is ported over."
|
30
|
+
|
31
|
+
issues_found = issues_found + klasses_with_deprecated.length
|
32
|
+
end
|
33
|
+
|
34
|
+
klasses_with_deprecated = resource_klasses.select { |klass| klass.methods.include?(:apply_includes) }
|
35
|
+
unless klasses_with_deprecated.empty?
|
36
|
+
puts " Found the following resources the still implement `apply_includes`:"
|
37
|
+
klasses_with_deprecated.each { |klass| puts " #{klass}"}
|
38
|
+
puts " The `apply_includes` method is no longer called by JR. Please review and ensure your functionality is ported over."
|
39
|
+
|
40
|
+
issues_found = issues_found + klasses_with_deprecated.length
|
41
|
+
end
|
42
|
+
|
43
|
+
if issues_found > 0
|
44
|
+
puts "Finished inspection. #{issues_found} issues found that may impact upgrading. Please address these issues. "
|
45
|
+
else
|
46
|
+
puts "Finished inspection with no issues found. Note this is only a cursory check for method overrides that will no \n" \
|
47
|
+
"longer be called by JSONAPI::Resources. This check in no way assures your code will continue to function as \n" \
|
48
|
+
"it did before the upgrade. Please do adequate testing before using in production."
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|