jsonapi-resources 0.9.3 → 0.10.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +5 -5
  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 +297 -0
  8. data/lib/jsonapi/active_relation_resource.rb +879 -0
  9. data/lib/jsonapi/acts_as_resource_controller.rb +122 -105
  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 +63 -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 -65
  19. data/lib/jsonapi/link_builder.rb +74 -80
  20. data/lib/jsonapi/operation.rb +16 -5
  21. data/lib/jsonapi/operation_result.rb +74 -16
  22. data/lib/jsonapi/path.rb +43 -0
  23. data/lib/jsonapi/path_segment.rb +76 -0
  24. data/lib/jsonapi/processor.rb +237 -110
  25. data/lib/jsonapi/relationship.rb +144 -15
  26. data/lib/jsonapi/request_parser.rb +412 -357
  27. data/lib/jsonapi/resource.rb +3 -1263
  28. data/lib/jsonapi/resource_controller_metal.rb +5 -2
  29. data/lib/jsonapi/resource_fragment.rb +47 -0
  30. data/lib/jsonapi/resource_id_tree.rb +112 -0
  31. data/lib/jsonapi/resource_identity.rb +42 -0
  32. data/lib/jsonapi/resource_serializer.rb +143 -285
  33. data/lib/jsonapi/resource_set.rb +176 -0
  34. data/lib/jsonapi/resources/railtie.rb +9 -0
  35. data/lib/jsonapi/resources/version.rb +1 -1
  36. data/lib/jsonapi/response_document.rb +105 -83
  37. data/lib/jsonapi/routing_ext.rb +48 -26
  38. data/lib/jsonapi-resources.rb +20 -4
  39. data/lib/tasks/check_upgrade.rake +52 -0
  40. metadata +47 -17
  41. data/lib/jsonapi/cached_resource_fragment.rb +0 -127
  42. data/lib/jsonapi/operation_dispatcher.rb +0 -88
  43. data/lib/jsonapi/operation_results.rb +0 -35
  44. 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.3'
3
+ VERSION = '0.10.5'
4
4
  end
5
5
  end
@@ -1,81 +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
- links[link_name] = @serializer.link_builder.relationships_related_link(result.source_resource, relationship, query_params(params))
71
- else
72
- links[link_name] = @serializer.query_link(query_params(params))
73
- 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))
74
127
  end
128
+ end
129
+ @top_level_links[link_name] = link unless link.blank?
75
130
  end
76
131
  end
132
+ end
77
133
 
78
- 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) }
79
136
  end
80
137
 
81
138
  def query_params(params)
@@ -96,40 +153,5 @@ module JSONAPI
96
153
 
97
154
  query_params
98
155
  end
99
-
100
- def results_to_hash
101
- if @operation_results.has_errors?
102
- { errors: @operation_results.all_errors }
103
- else
104
- if @operation_results.results.length == 1
105
- result = @operation_results.results[0]
106
-
107
- case result
108
- when JSONAPI::ResourceOperationResult
109
- @serializer.serialize_to_hash(result.resource)
110
- when JSONAPI::ResourcesOperationResult
111
- @serializer.serialize_to_hash(result.resources)
112
- when JSONAPI::LinksObjectOperationResult
113
- @serializer.serialize_to_links_hash(result.parent_resource,
114
- result.relationship)
115
- when JSONAPI::OperationResult
116
- {}
117
- end
118
-
119
- elsif @operation_results.results.length > 1
120
- resources = []
121
- @operation_results.results.each do |result|
122
- case result
123
- when JSONAPI::ResourceOperationResult
124
- resources.push(result.resource)
125
- when JSONAPI::ResourcesOperationResult
126
- resources.concat(result.resources)
127
- end
128
- end
129
-
130
- @serializer.serialize_to_hash(resources)
131
- end
132
- end
133
- end
134
156
  end
135
157
  end
@@ -18,7 +18,13 @@ 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
+
23
+ res._routed = true
24
+
25
+ unless res.singleton?
26
+ warn "Singleton routes created for non singleton resource #{res}. Links may not be generated correctly."
27
+ end
22
28
 
23
29
  options = resources.extract_options!.dup
24
30
  options[:controller] ||= @resource_type
@@ -33,8 +39,8 @@ module ActionDispatch
33
39
  end
34
40
 
35
41
  if res._immutable
36
- options[:except] << :create unless options[:except].include?(:create) || options[:except].include?('create')
37
- 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')
38
44
  options[:except] << :destroy unless options[:except].include?(:destroy) || options[:except].include?('destroy')
39
45
  end
40
46
 
@@ -64,7 +70,7 @@ module ActionDispatch
64
70
  end
65
71
 
66
72
  def jsonapi_relationships(options = {})
67
- 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))
68
74
  res._relationships.each do |relationship_name, relationship|
69
75
  if relationship.is_a?(JSONAPI::Relationship::ToMany)
70
76
  jsonapi_links(relationship_name, options)
@@ -78,7 +84,13 @@ module ActionDispatch
78
84
 
79
85
  def jsonapi_resources(*resources, &_block)
80
86
  @resource_type = resources.first
81
- 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
+
89
+ res._routed = true
90
+
91
+ if res.singleton?
92
+ warn "Singleton resource #{res} should use `jsonapi_resource` instead."
93
+ end
82
94
 
83
95
  options = resources.extract_options!.dup
84
96
  options[:controller] ||= @resource_type
@@ -102,8 +114,8 @@ module ActionDispatch
102
114
  end
103
115
 
104
116
  if res._immutable
105
- options[:except] << :create unless options[:except].include?(:create) || options[:except].include?('create')
106
- 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')
107
119
  options[:except] << :destroy unless options[:except].include?(:destroy) || options[:except].include?('destroy')
108
120
  end
109
121
 
@@ -147,25 +159,26 @@ module ActionDispatch
147
159
  formatted_relationship_name = format_route(link_type)
148
160
  options = links.extract_options!.dup
149
161
 
150
- res = JSONAPI::Resource.resource_for(resource_type_with_module_prefix)
162
+ res = JSONAPI::Resource.resource_klass_for(resource_type_with_module_prefix)
151
163
  options[:controller] ||= res._type.to_s
152
164
 
153
165
  methods = links_methods(options)
154
166
 
155
167
  if methods.include?(:show)
156
168
  match "relationships/#{formatted_relationship_name}", controller: options[:controller],
157
- action: 'show_relationship', relationship: link_type.to_s, via: [:get]
169
+ action: 'show_relationship', relationship: link_type.to_s, via: [:get],
170
+ as: "relationships/#{link_type}"
158
171
  end
159
172
 
160
173
  if res.mutable?
161
174
  if methods.include?(:update)
162
175
  match "relationships/#{formatted_relationship_name}", controller: options[:controller],
163
- action: 'update_relationship', relationship: link_type.to_s, via: [:put, :patch]
176
+ action: 'update_relationship', relationship: link_type.to_s, via: [:put, :patch]
164
177
  end
165
178
 
166
179
  if methods.include?(:destroy)
167
180
  match "relationships/#{formatted_relationship_name}", controller: options[:controller],
168
- action: 'destroy_relationship', relationship: link_type.to_s, via: [:delete]
181
+ action: 'destroy_relationship', relationship: link_type.to_s, via: [:delete]
169
182
  end
170
183
  end
171
184
  end
@@ -175,69 +188,77 @@ module ActionDispatch
175
188
  formatted_relationship_name = format_route(link_type)
176
189
  options = links.extract_options!.dup
177
190
 
178
- res = JSONAPI::Resource.resource_for(resource_type_with_module_prefix)
191
+ res = JSONAPI::Resource.resource_klass_for(resource_type_with_module_prefix)
179
192
  options[:controller] ||= res._type.to_s
180
193
 
181
194
  methods = links_methods(options)
182
195
 
183
196
  if methods.include?(:show)
184
197
  match "relationships/#{formatted_relationship_name}", controller: options[:controller],
185
- action: 'show_relationship', relationship: link_type.to_s, via: [:get]
198
+ action: 'show_relationship', relationship: link_type.to_s, via: [:get],
199
+ as: "relationships/#{link_type}"
186
200
  end
187
201
 
188
202
  if res.mutable?
189
203
  if methods.include?(:create)
190
204
  match "relationships/#{formatted_relationship_name}", controller: options[:controller],
191
- action: 'create_relationship', relationship: link_type.to_s, via: [:post]
205
+ action: 'create_relationship', relationship: link_type.to_s, via: [:post]
192
206
  end
193
207
 
194
208
  if methods.include?(:update)
195
209
  match "relationships/#{formatted_relationship_name}", controller: options[:controller],
196
- action: 'update_relationship', relationship: link_type.to_s, via: [:put, :patch]
210
+ action: 'update_relationship', relationship: link_type.to_s, via: [:put, :patch]
197
211
  end
198
212
 
199
213
  if methods.include?(:destroy)
200
214
  match "relationships/#{formatted_relationship_name}", controller: options[:controller],
201
- action: 'destroy_relationship', relationship: link_type.to_s, via: [:delete]
215
+ action: 'destroy_relationship', relationship: link_type.to_s, via: [:delete]
202
216
  end
203
217
  end
204
218
  end
205
219
 
206
220
  def jsonapi_related_resource(*relationship)
207
- source = JSONAPI::Resource.resource_for(resource_type_with_module_prefix)
221
+ source = JSONAPI::Resource.resource_klass_for(resource_type_with_module_prefix)
208
222
  options = relationship.extract_options!.dup
209
223
 
210
224
  relationship_name = relationship.first
211
225
  relationship = source._relationships[relationship_name]
212
226
 
227
+ relationship._routed = true
228
+
213
229
  formatted_relationship_name = format_route(relationship.name)
214
230
 
215
231
  if relationship.polymorphic?
216
232
  options[:controller] ||= relationship.class_name.underscore.pluralize
217
233
  else
218
- 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))
219
235
  options[:controller] ||= related_resource._type.to_s
220
236
  end
221
237
 
222
- match "#{formatted_relationship_name}", controller: options[:controller],
223
- relationship: relationship.name, source: resource_type_with_module_prefix(source._type),
224
- action: 'get_related_resource', via: [:get]
238
+ match formatted_relationship_name, controller: options[:controller],
239
+ relationship: relationship.name, source: resource_type_with_module_prefix(source._type),
240
+ action: 'show_related_resource', via: [:get],
241
+ as: "related/#{relationship_name}"
225
242
  end
226
243
 
227
244
  def jsonapi_related_resources(*relationship)
228
- source = JSONAPI::Resource.resource_for(resource_type_with_module_prefix)
245
+ source = JSONAPI::Resource.resource_klass_for(resource_type_with_module_prefix)
229
246
  options = relationship.extract_options!.dup
230
247
 
231
248
  relationship_name = relationship.first
232
249
  relationship = source._relationships[relationship_name]
233
250
 
251
+ relationship._routed = true
252
+
234
253
  formatted_relationship_name = format_route(relationship.name)
235
- 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))
236
255
  options[:controller] ||= related_resource._type.to_s
237
256
 
238
- match "#{formatted_relationship_name}", controller: options[:controller],
239
- relationship: relationship.name, source: resource_type_with_module_prefix(source._type),
240
- action: 'get_related_resources', via: [:get]
257
+ match formatted_relationship_name,
258
+ controller: options[:controller],
259
+ relationship: relationship.name, source: resource_type_with_module_prefix(source._type),
260
+ action: 'index_related_resources', via: [:get],
261
+ as: "related/#{relationship_name}"
241
262
  end
242
263
 
243
264
  protected
@@ -250,6 +271,7 @@ module ActionDispatch
250
271
  @scope = @scope.parent
251
272
  end
252
273
  # :nocov:
274
+
253
275
  private
254
276
 
255
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'