jsonapi-resources 0.9.12 → 0.10.7

Sign up to get free protection for your applications and to get access to all the features.
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 +18 -25
  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 -24
  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 +3 -0
  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 +34 -31
  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.12'
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