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.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +34 -11
  4. data/lib/bug_report_templates/rails_5_latest.rb +125 -0
  5. data/lib/bug_report_templates/rails_5_master.rb +140 -0
  6. data/lib/jsonapi/active_relation/adapters/join_left_active_record_adapter.rb +27 -0
  7. data/lib/jsonapi/active_relation/join_manager.rb +303 -0
  8. data/lib/jsonapi/active_relation_resource.rb +884 -0
  9. data/lib/jsonapi/acts_as_resource_controller.rb +122 -106
  10. data/lib/jsonapi/basic_resource.rb +1162 -0
  11. data/lib/jsonapi/cached_response_fragment.rb +127 -0
  12. data/lib/jsonapi/compiled_json.rb +11 -1
  13. data/lib/jsonapi/configuration.rb +57 -8
  14. data/lib/jsonapi/error.rb +27 -0
  15. data/lib/jsonapi/error_codes.rb +2 -0
  16. data/lib/jsonapi/exceptions.rb +63 -40
  17. data/lib/jsonapi/formatter.rb +3 -3
  18. data/lib/jsonapi/include_directives.rb +18 -75
  19. data/lib/jsonapi/link_builder.rb +16 -19
  20. data/lib/jsonapi/operation.rb +16 -5
  21. data/lib/jsonapi/operation_result.rb +73 -15
  22. data/lib/jsonapi/paginator.rb +17 -0
  23. data/lib/jsonapi/path.rb +43 -0
  24. data/lib/jsonapi/path_segment.rb +76 -0
  25. data/lib/jsonapi/processor.rb +246 -111
  26. data/lib/jsonapi/relationship.rb +117 -18
  27. data/lib/jsonapi/request_parser.rb +383 -396
  28. data/lib/jsonapi/resource.rb +3 -1376
  29. data/lib/jsonapi/resource_controller_metal.rb +5 -2
  30. data/lib/jsonapi/resource_fragment.rb +47 -0
  31. data/lib/jsonapi/resource_id_tree.rb +112 -0
  32. data/lib/jsonapi/resource_identity.rb +42 -0
  33. data/lib/jsonapi/resource_serializer.rb +124 -286
  34. data/lib/jsonapi/resource_set.rb +176 -0
  35. data/lib/jsonapi/resources/railtie.rb +9 -0
  36. data/lib/jsonapi/resources/version.rb +1 -1
  37. data/lib/jsonapi/response_document.rb +104 -87
  38. data/lib/jsonapi/routing_ext.rb +19 -21
  39. data/lib/jsonapi-resources.rb +20 -4
  40. data/lib/tasks/check_upgrade.rake +52 -0
  41. metadata +36 -33
  42. data/lib/jsonapi/cached_resource_fragment.rb +0 -127
  43. data/lib/jsonapi/operation_dispatcher.rb +0 -88
  44. data/lib/jsonapi/operation_results.rb +0 -35
  45. 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
@@ -0,0 +1,9 @@
1
+ module JSONAPI
2
+ module Resources
3
+ class Railtie < Rails::Railtie
4
+ rake_tasks do
5
+ load 'tasks/check_upgrade.rake'
6
+ end
7
+ end
8
+ end
9
+ end
@@ -1,5 +1,5 @@
1
1
  module JSONAPI
2
2
  module Resources
3
- VERSION = '0.9.11'
3
+ VERSION = '0.10.7'
4
4
  end
5
5
  end
@@ -1,86 +1,138 @@
1
1
  module JSONAPI
2
2
  class ResponseDocument
3
- def initialize(operation_results, serializer, options = {})
4
- @operation_results = operation_results
5
- @serializer = serializer
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 contents
12
- hash = results_to_hash
19
+ def has_errors?
20
+ @error_results.length > 0 || @global_errors.length > 0
21
+ end
13
22
 
14
- meta = top_level_meta
15
- hash.merge!(meta: meta) unless meta.empty?
23
+ def add_result(result, operation)
24
+ if result.is_a?(JSONAPI::ErrorsOperationResult)
25
+ # Clear any serialized results
26
+ @serialized_results = []
16
27
 
17
- links = top_level_links
18
- hash.merge!(links: links) unless links.empty?
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
- hash
40
+ def add_global_error(error)
41
+ @global_errors.push error
21
42
  end
22
43
 
23
- def status
24
- if @operation_results.has_errors?
25
- @operation_results.all_errors[0].status
44
+ def contents
45
+ if has_errors?
46
+ return { 'errors' => @global_errors }
26
47
  else
27
- @operation_results.results[0].code
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
- private
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
- # Rolls up the top level meta data from the base_meta, the set of operations,
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
- meta.merge!(@operation_results.meta)
88
+ def update_meta(result)
89
+ @top_level_meta.merge!(result.meta)
39
90
 
40
- @operation_results.results.each do |result|
41
- meta.merge!(result.meta)
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
- if JSONAPI.configuration.top_level_meta_include_record_count && result.respond_to?(:record_count)
44
- meta[JSONAPI.configuration.top_level_meta_record_count_key] = result.record_count
45
- end
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
- if JSONAPI.configuration.top_level_meta_include_page_count && result.respond_to?(:page_count)
48
- meta[JSONAPI.configuration.top_level_meta_page_count_key] = result.page_count
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
- meta.as_json.deep_transform_keys { |key| @key_formatter.format(key) }
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
- # Rolls up the top level links from the base_links, the set of operations,
56
- # and the result of each operation. The keys are then formatted.
57
- def top_level_links
58
- links = @options.fetch(:base_links, {})
59
-
60
- links.merge!(@operation_results.links)
61
-
62
- @operation_results.results.each do |result|
63
- links.merge!(result.links)
64
-
65
- # Build pagination links
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
- 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))
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
- links.deep_transform_keys { |key| @key_formatter.format(key) }
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
@@ -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.resource_for(resource_type_with_module_prefix(@resource_type))
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 unless options[:except].include?(:create) || options[:except].include?('create')
43
- options[:except] << :update unless options[:except].include?(:update) || options[:except].include?('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.resource_for(resource_type_with_module_prefix(@resource_type))
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.resource_for(resource_type_with_module_prefix(@resource_type))
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 unless options[:except].include?(:create) || options[:except].include?('create')
118
- options[:except] << :update unless options[:except].include?(:update) || options[:except].include?('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.resource_for(resource_type_with_module_prefix)
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.resource_for(resource_type_with_module_prefix)
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.resource_for(resource_type_with_module_prefix)
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.resource_for(resource_type_with_module_prefix(relationship.class_name.underscore.pluralize))
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: 'get_related_resource', via: [:get],
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.resource_for(resource_type_with_module_prefix)
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.resource_for(resource_type_with_module_prefix(relationship.class_name.underscore))
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: 'get_related_resources', via: [:get],
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)
@@ -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/cached_resource_fragment'
7
+ require 'jsonapi/cached_response_fragment'
5
8
  require 'jsonapi/response_document'
6
9
  require 'jsonapi/acts_as_resource_controller'
7
- require 'jsonapi/resource_controller'
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