jsonapi-resources 0.7.1.beta1 → 0.7.1.beta2

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 (93) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +248 -74
  3. data/lib/jsonapi-resources.rb +5 -3
  4. data/lib/jsonapi/acts_as_resource_controller.rb +77 -14
  5. data/lib/jsonapi/configuration.rb +77 -16
  6. data/lib/jsonapi/error.rb +12 -0
  7. data/lib/jsonapi/error_codes.rb +2 -0
  8. data/lib/jsonapi/exceptions.rb +29 -9
  9. data/lib/jsonapi/formatter.rb +29 -4
  10. data/lib/jsonapi/link_builder.rb +18 -18
  11. data/lib/jsonapi/mime_types.rb +25 -6
  12. data/lib/jsonapi/naive_cache.rb +30 -0
  13. data/lib/jsonapi/operation.rb +10 -342
  14. data/lib/jsonapi/operation_dispatcher.rb +87 -0
  15. data/lib/jsonapi/operation_result.rb +2 -1
  16. data/lib/jsonapi/paginator.rb +6 -2
  17. data/lib/jsonapi/processor.rb +283 -0
  18. data/lib/jsonapi/relationship.rb +6 -4
  19. data/lib/jsonapi/{request.rb → request_parser.rb} +46 -35
  20. data/lib/jsonapi/resource.rb +88 -13
  21. data/lib/jsonapi/resource_controller.rb +2 -14
  22. data/lib/jsonapi/resource_controller_metal.rb +17 -0
  23. data/lib/jsonapi/resource_serializer.rb +62 -47
  24. data/lib/jsonapi/resources/version.rb +1 -1
  25. data/lib/jsonapi/response_document.rb +13 -2
  26. data/lib/jsonapi/routing_ext.rb +49 -11
  27. metadata +37 -129
  28. data/.gitignore +0 -22
  29. data/.travis.yml +0 -9
  30. data/Gemfile +0 -23
  31. data/Rakefile +0 -20
  32. data/jsonapi-resources.gemspec +0 -29
  33. data/lib/jsonapi/active_record_operations_processor.rb +0 -35
  34. data/lib/jsonapi/operations_processor.rb +0 -120
  35. data/locales/en.yml +0 -80
  36. data/test/config/database.yml +0 -5
  37. data/test/controllers/controller_test.rb +0 -3312
  38. data/test/fixtures/active_record.rb +0 -1486
  39. data/test/fixtures/author_details.yml +0 -9
  40. data/test/fixtures/book_authors.yml +0 -3
  41. data/test/fixtures/book_comments.yml +0 -12
  42. data/test/fixtures/books.yml +0 -7
  43. data/test/fixtures/categories.yml +0 -35
  44. data/test/fixtures/comments.yml +0 -21
  45. data/test/fixtures/comments_tags.yml +0 -20
  46. data/test/fixtures/companies.yml +0 -4
  47. data/test/fixtures/craters.yml +0 -9
  48. data/test/fixtures/customers.yml +0 -11
  49. data/test/fixtures/documents.yml +0 -3
  50. data/test/fixtures/expense_entries.yml +0 -13
  51. data/test/fixtures/facts.yml +0 -11
  52. data/test/fixtures/hair_cuts.yml +0 -3
  53. data/test/fixtures/iso_currencies.yml +0 -17
  54. data/test/fixtures/line_items.yml +0 -37
  55. data/test/fixtures/makes.yml +0 -2
  56. data/test/fixtures/moons.yml +0 -6
  57. data/test/fixtures/numeros_telefone.yml +0 -3
  58. data/test/fixtures/order_flags.yml +0 -7
  59. data/test/fixtures/people.yml +0 -31
  60. data/test/fixtures/pictures.yml +0 -15
  61. data/test/fixtures/planet_types.yml +0 -19
  62. data/test/fixtures/planets.yml +0 -47
  63. data/test/fixtures/posts.yml +0 -102
  64. data/test/fixtures/posts_tags.yml +0 -59
  65. data/test/fixtures/preferences.yml +0 -14
  66. data/test/fixtures/products.yml +0 -3
  67. data/test/fixtures/purchase_orders.yml +0 -23
  68. data/test/fixtures/sections.yml +0 -8
  69. data/test/fixtures/tags.yml +0 -39
  70. data/test/fixtures/vehicles.yml +0 -17
  71. data/test/fixtures/web_pages.yml +0 -3
  72. data/test/helpers/assertions.rb +0 -13
  73. data/test/helpers/functional_helpers.rb +0 -59
  74. data/test/helpers/value_matchers.rb +0 -60
  75. data/test/helpers/value_matchers_test.rb +0 -40
  76. data/test/integration/requests/namespaced_model_test.rb +0 -13
  77. data/test/integration/requests/request_test.rb +0 -932
  78. data/test/integration/routes/routes_test.rb +0 -218
  79. data/test/integration/sti_fields_test.rb +0 -18
  80. data/test/lib/generators/jsonapi/controller_generator_test.rb +0 -25
  81. data/test/lib/generators/jsonapi/resource_generator_test.rb +0 -30
  82. data/test/test_helper.rb +0 -342
  83. data/test/unit/formatters/dasherized_key_formatter_test.rb +0 -8
  84. data/test/unit/jsonapi_request/jsonapi_request_test.rb +0 -199
  85. data/test/unit/operation/operations_processor_test.rb +0 -528
  86. data/test/unit/pagination/offset_paginator_test.rb +0 -245
  87. data/test/unit/pagination/paged_paginator_test.rb +0 -242
  88. data/test/unit/resource/resource_test.rb +0 -560
  89. data/test/unit/serializer/include_directives_test.rb +0 -113
  90. data/test/unit/serializer/link_builder_test.rb +0 -244
  91. data/test/unit/serializer/polymorphic_serializer_test.rb +0 -383
  92. data/test/unit/serializer/response_document_test.rb +0 -61
  93. data/test/unit/serializer/serializer_test.rb +0 -1939
@@ -9,9 +9,12 @@ module JSONAPI
9
9
  arg
10
10
  end
11
11
 
12
+ def cached
13
+ return FormatterWrapperCache.new(self)
14
+ end
15
+
12
16
  def formatter_for(format)
13
- formatter_class_name = "#{format.to_s.camelize}Formatter"
14
- formatter_class_name.safe_constantize
17
+ "#{format.to_s.camelize}Formatter".safe_constantize
15
18
  end
16
19
  end
17
20
  end
@@ -51,11 +54,33 @@ module JSONAPI
51
54
  end
52
55
 
53
56
  def value_formatter_for(type)
54
- formatter_name = "#{type.to_s.camelize}Value"
55
- formatter_for(formatter_name)
57
+ "#{type.to_s.camelize}ValueFormatter".safe_constantize
56
58
  end
57
59
  end
58
60
  end
61
+
62
+ # Warning: Not thread-safe. Wrap in ThreadLocalVar as needed.
63
+ class FormatterWrapperCache
64
+ attr_reader :formatter_klass
65
+
66
+ def initialize(formatter_klass)
67
+ @formatter_klass = formatter_klass
68
+ @format_cache = NaiveCache.new{|arg| formatter_klass.format(arg) }
69
+ @unformat_cache = NaiveCache.new{|arg| formatter_klass.unformat(arg) }
70
+ end
71
+
72
+ def format(arg)
73
+ @format_cache.get(arg)
74
+ end
75
+
76
+ def unformat(arg)
77
+ @unformat_cache.get(arg)
78
+ end
79
+
80
+ def cached
81
+ self
82
+ end
83
+ end
59
84
  end
60
85
 
61
86
  class UnderscoredKeyFormatter < JSONAPI::KeyFormatter
@@ -2,21 +2,24 @@ module JSONAPI
2
2
  class LinkBuilder
3
3
  attr_reader :base_url,
4
4
  :primary_resource_klass,
5
- :route_formatter
5
+ :route_formatter,
6
+ :engine_name
6
7
 
7
8
  def initialize(config = {})
8
9
  @base_url = config[:base_url]
9
10
  @primary_resource_klass = config[:primary_resource_klass]
10
11
  @route_formatter = config[:route_formatter]
11
- @is_engine = !!engine_name
12
- end
12
+ @engine_name = build_engine_name
13
13
 
14
- def engine?
15
- @is_engine
14
+ # Warning: These make LinkBuilder non-thread-safe. That's not a problem with the
15
+ # request-specific way it's currently used, though.
16
+ @resources_path_cache = JSONAPI::NaiveCache.new do |source_klass|
17
+ formatted_module_path_from_class(source_klass) + format_route(source_klass._type.to_s)
18
+ end
16
19
  end
17
20
 
18
- def engine_name
19
- @engine_name ||= build_engine_name
21
+ def engine?
22
+ !!@engine_name
20
23
  end
21
24
 
22
25
  def primary_resources_url
@@ -96,14 +99,14 @@ module JSONAPI
96
99
  end
97
100
 
98
101
  def format_route(route)
99
- route_formatter.format(route.to_s)
102
+ route_formatter.format(route)
100
103
  end
101
104
 
102
105
  def formatted_module_path_from_class(klass)
103
106
  scopes = module_scopes_from_class(klass)
104
107
 
105
108
  unless scopes.empty?
106
- "/#{ scopes.map(&:underscore).join('/') }/"
109
+ "/#{ scopes.map{ |scope| format_route(scope.to_s.underscore) }.join('/') }/"
107
110
  else
108
111
  "/"
109
112
  end
@@ -113,11 +116,12 @@ module JSONAPI
113
116
  klass.name.to_s.split("::")[0...-1]
114
117
  end
115
118
 
119
+ def regular_resources_path(source_klass)
120
+ @resources_path_cache.get(source_klass)
121
+ end
122
+
116
123
  def regular_primary_resources_path
117
- [
118
- formatted_module_path_from_class(primary_resource_klass),
119
- format_route(primary_resource_klass._type.to_s),
120
- ].join
124
+ regular_resources_path(primary_resource_klass)
121
125
  end
122
126
 
123
127
  def regular_primary_resources_url
@@ -125,11 +129,7 @@ module JSONAPI
125
129
  end
126
130
 
127
131
  def regular_resource_path(source)
128
- [
129
- formatted_module_path_from_class(source.class),
130
- format_route(source.class._type.to_s),
131
- "/#{ source.id }",
132
- ].join
132
+ "#{regular_resources_path(source.class)}/#{source.id}"
133
133
  end
134
134
 
135
135
  def regular_resource_url(source)
@@ -1,11 +1,30 @@
1
1
  module JSONAPI
2
2
  MEDIA_TYPE = 'application/vnd.api+json'
3
- end
4
3
 
5
- Mime::Type.register JSONAPI::MEDIA_TYPE, :api_json
4
+ module MimeTypes
5
+ def self.install
6
+ Mime::Type.register JSONAPI::MEDIA_TYPE, :api_json
7
+
8
+ # :nocov:
9
+ if Rails::VERSION::MAJOR >= 5
10
+ parsers = ActionDispatch::Request.parameter_parsers.merge(
11
+ Mime::Type.lookup(JSONAPI::MEDIA_TYPE).symbol => parser
12
+ )
13
+ ActionDispatch::Request.parameter_parsers = parsers
14
+ else
15
+ ActionDispatch::ParamsParser::DEFAULT_PARSERS[Mime::Type.lookup(JSONAPI::MEDIA_TYPE)] = parser
16
+ end
17
+ # :nocov:
18
+ end
19
+
20
+ def self.parser
21
+ lambda do |body|
22
+ data = JSON.parse(body)
23
+ data = {:_json => data} unless data.is_a?(Hash)
24
+ data.with_indifferent_access
25
+ end
26
+ end
27
+ end
6
28
 
7
- ActionDispatch::ParamsParser::DEFAULT_PARSERS[Mime::Type.lookup(JSONAPI::MEDIA_TYPE)] = lambda do |body|
8
- data = JSON.parse(body)
9
- data = {:_json => data} unless data.is_a?(Hash)
10
- data.with_indifferent_access
29
+ MimeTypes.install
11
30
  end
@@ -0,0 +1,30 @@
1
+ module JSONAPI
2
+
3
+ # Cache which memoizes the given block.
4
+ #
5
+ # It's "naive" because it clears the least-recently-inserted cache entry
6
+ # rather than the least-recently-used. This makes lookups faster but cache
7
+ # misses more frequent after cleanups. Therefore you the best time to use
8
+ # this cache is when you expect only a small number of unique lookup keys, so
9
+ # that the cache never has to clear.
10
+ #
11
+ # Also, it's not thread safe (although jsonapi-resources is careful to only
12
+ # use it in a thread safe way).
13
+ class NaiveCache
14
+ def initialize(cap = 10000, &calculator)
15
+ @cap = cap
16
+ @data = {}
17
+ @calculator = calculator
18
+ end
19
+
20
+ def get(key)
21
+ found = true
22
+ value = @data.fetch(key) { found = false }
23
+ return value if found
24
+ value = @calculator.call(key)
25
+ @data[key] = value
26
+ @data.shift if @data.length > @cap
27
+ return value
28
+ end
29
+ end
30
+ end
@@ -1,356 +1,24 @@
1
1
  module JSONAPI
2
2
  class Operation
3
- attr_reader :resource_klass, :options, :transactional
3
+ attr_reader :resource_klass, :operation_type, :options
4
4
 
5
- def initialize(resource_klass, options = {})
6
- @context = options[:context]
5
+ def initialize(operation_type, resource_klass, options)
6
+ @operation_type = operation_type
7
7
  @resource_klass = resource_klass
8
8
  @options = options
9
- @transactional = true
10
9
  end
11
10
 
12
- def apply
11
+ def transactional?
12
+ JSONAPI::Processor._processor_from_resource_type(resource_klass).transactional_operation_type?(operation_type)
13
13
  end
14
- end
15
-
16
- class FindOperation < Operation
17
- attr_reader :filters, :include_directives, :sort_criteria, :paginator
18
-
19
- def initialize(resource_klass, options = {})
20
- super(resource_klass, options)
21
- @filters = options[:filters]
22
- @include_directives = options[:include_directives]
23
- @sort_criteria = options.fetch(:sort_criteria, [])
24
- @paginator = options[:paginator]
25
- @transactional = false
26
- end
27
-
28
- def record_count
29
- @_record_count ||= @resource_klass.find_count(@resource_klass.verify_filters(@filters, @context),
30
- context: @context,
31
- include_directives: @include_directives)
32
- end
33
-
34
- def pagination_params
35
- if @paginator && JSONAPI.configuration.top_level_links_include_pagination
36
- options = {}
37
- options[:record_count] = record_count if @paginator.class.requires_record_count
38
- return @paginator.links_page_params(options)
39
- else
40
- return {}
41
- end
42
- end
43
-
44
- def apply
45
- resource_records = @resource_klass.find(@resource_klass.verify_filters(@filters, @context),
46
- context: @context,
47
- include_directives: @include_directives,
48
- sort_criteria: @sort_criteria,
49
- paginator: @paginator)
50
-
51
- options = {}
52
- if JSONAPI.configuration.top_level_links_include_pagination
53
- options[:pagination_params] = pagination_params
54
- end
55
-
56
- if JSONAPI.configuration.top_level_meta_include_record_count
57
- options[:record_count] = record_count
58
- end
59
-
60
- return JSONAPI::ResourcesOperationResult.new(:ok,
61
- resource_records,
62
- options)
63
-
64
- rescue JSONAPI::Exceptions::Error => e
65
- return JSONAPI::ErrorsOperationResult.new(e.errors[0].code, e.errors)
66
- end
67
- end
68
-
69
- class ShowOperation < Operation
70
- attr_reader :id, :include_directives
71
-
72
- def initialize(resource_klass, options = {})
73
- super(resource_klass, options)
74
- @id = options.fetch(:id)
75
- @include_directives = options[:include_directives]
76
- @transactional = false
77
- end
78
-
79
- def apply
80
- key = @resource_klass.verify_key(@id, @context)
81
-
82
- resource_record = @resource_klass.find_by_key(key,
83
- context: @context,
84
- include_directives: @include_directives)
85
-
86
- return JSONAPI::ResourceOperationResult.new(:ok, resource_record)
87
-
88
- rescue JSONAPI::Exceptions::Error => e
89
- return JSONAPI::ErrorsOperationResult.new(e.errors[0].code, e.errors)
90
- end
91
- end
92
-
93
- class ShowRelationshipOperation < Operation
94
- attr_reader :parent_key, :relationship_type
95
-
96
- def initialize(resource_klass, options = {})
97
- super(resource_klass, options)
98
- @parent_key = options.fetch(:parent_key)
99
- @relationship_type = options.fetch(:relationship_type)
100
- @transactional = false
101
- end
102
-
103
- def apply
104
- parent_resource = resource_klass.find_by_key(@parent_key, context: @context)
105
-
106
- return JSONAPI::LinksObjectOperationResult.new(:ok,
107
- parent_resource,
108
- resource_klass._relationship(@relationship_type))
109
-
110
- rescue JSONAPI::Exceptions::Error => e
111
- return JSONAPI::ErrorsOperationResult.new(e.errors[0].code, e.errors)
112
- end
113
- end
114
-
115
- class ShowRelatedResourceOperation < Operation
116
- attr_reader :source_klass, :source_id, :relationship_type
117
-
118
- def initialize(resource_klass, options = {})
119
- super(resource_klass, options)
120
- @source_klass = options.fetch(:source_klass)
121
- @source_id = options.fetch(:source_id)
122
- @relationship_type = options.fetch(:relationship_type)
123
- @transactional = false
124
- end
125
-
126
- def apply
127
- source_resource = @source_klass.find_by_key(@source_id, context: @context)
128
-
129
- related_resource = source_resource.public_send(@relationship_type)
130
-
131
- return JSONAPI::ResourceOperationResult.new(:ok, related_resource)
132
-
133
- rescue JSONAPI::Exceptions::Error => e
134
- return JSONAPI::ErrorsOperationResult.new(e.errors[0].code, e.errors)
135
- end
136
- end
137
-
138
- class ShowRelatedResourcesOperation < Operation
139
- attr_reader :source_klass, :source_id, :relationship_type, :filters, :sort_criteria, :paginator
140
-
141
- def initialize(resource_klass, options = {})
142
- super(resource_klass, options)
143
- @source_klass = options.fetch(:source_klass)
144
- @source_id = options.fetch(:source_id)
145
- @relationship_type = options.fetch(:relationship_type)
146
- @filters = options[:filters]
147
- @sort_criteria = options[:sort_criteria]
148
- @paginator = options[:paginator]
149
- @transactional = false
150
- end
151
-
152
- def record_count
153
- @_record_count ||= records.count(:all)
154
- end
155
-
156
- def source_resource
157
- @_source_resource ||= @source_klass.find_by_key(@source_id, context: @context)
158
- end
159
-
160
- def records
161
- related_resource_records = source_resource.public_send("records_for_" + @relationship_type)
162
- @resource_klass.filter_records(@filters, @options, related_resource_records)
163
- end
164
-
165
- def pagination_params
166
- if @paginator && JSONAPI.configuration.top_level_links_include_pagination
167
- options = {}
168
- options[:record_count] = record_count if @paginator.class.requires_record_count
169
- @paginator.links_page_params(options)
170
- else
171
- {}
172
- end
173
- end
174
-
175
- def options
176
- opts = {}
177
- opts.merge!(pagination_params: pagination_params) if JSONAPI.configuration.top_level_links_include_pagination
178
- opts.merge!(record_count: record_count) if JSONAPI.configuration.top_level_meta_include_record_count
179
- opts
180
- end
181
-
182
- def apply
183
- related_resource = source_resource.public_send(@relationship_type,
184
- filters: @filters,
185
- sort_criteria: @sort_criteria,
186
- paginator: @paginator)
187
-
188
- return JSONAPI::RelatedResourcesOperationResult.new(:ok, source_resource, @relationship_type, related_resource, options)
189
-
190
- rescue JSONAPI::Exceptions::Error => e
191
- return JSONAPI::ErrorsOperationResult.new(e.errors[0].code, e.errors)
192
- end
193
- end
194
14
 
195
- class CreateResourceOperation < Operation
196
- attr_reader :data
197
-
198
- def initialize(resource_klass, options = {})
199
- super(resource_klass, options)
200
- @data = options.fetch(:data)
201
- end
202
-
203
- def apply
204
- resource = @resource_klass.create(@context)
205
- result = resource.replace_fields(@data)
206
-
207
- return JSONAPI::ResourceOperationResult.new((result == :completed ? :created : :accepted), resource)
208
-
209
- rescue JSONAPI::Exceptions::Error => e
210
- return JSONAPI::ErrorsOperationResult.new(e.errors[0].code, e.errors)
211
- end
212
- end
213
-
214
- class RemoveResourceOperation < Operation
215
- attr_reader :resource_id
216
- def initialize(resource_klass, options = {})
217
- super(resource_klass, options)
218
- @resource_id = options.fetch(:resource_id)
219
- end
220
-
221
- def apply
222
- resource = @resource_klass.find_by_key(@resource_id, context: @context)
223
- result = resource.remove
224
-
225
- return JSONAPI::OperationResult.new(result == :completed ? :no_content : :accepted)
226
-
227
- rescue JSONAPI::Exceptions::Error => e
228
- return JSONAPI::ErrorsOperationResult.new(e.errors[0].code, e.errors)
229
- end
230
- end
231
-
232
- class ReplaceFieldsOperation < Operation
233
- attr_reader :data, :resource_id
234
-
235
- def initialize(resource_klass, options = {})
236
- super(resource_klass, options)
237
- @resource_id = options.fetch(:resource_id)
238
- @data = options.fetch(:data)
239
- end
240
-
241
- def apply
242
- resource = @resource_klass.find_by_key(@resource_id, context: @context)
243
- result = resource.replace_fields(data)
244
-
245
- return JSONAPI::ResourceOperationResult.new(result == :completed ? :ok : :accepted, resource)
246
- end
247
- end
248
-
249
- class ReplaceToOneRelationshipOperation < Operation
250
- attr_reader :resource_id, :relationship_type, :key_value
251
-
252
- def initialize(resource_klass, options = {})
253
- super(resource_klass, options)
254
- @resource_id = options.fetch(:resource_id)
255
- @key_value = options.fetch(:key_value)
256
- @relationship_type = options.fetch(:relationship_type).to_sym
257
- end
258
-
259
- def apply
260
- resource = @resource_klass.find_by_key(@resource_id, context: @context)
261
- result = resource.replace_to_one_link(@relationship_type, @key_value)
262
-
263
- return JSONAPI::OperationResult.new(result == :completed ? :no_content : :accepted)
264
- end
265
- end
266
-
267
- class ReplacePolymorphicToOneRelationshipOperation < Operation
268
- attr_reader :resource_id, :relationship_type, :key_value, :key_type
269
-
270
- def initialize(resource_klass, options = {})
271
- super(resource_klass, options)
272
- @resource_id = options.fetch(:resource_id)
273
- @key_value = options.fetch(:key_value)
274
- @key_type = options.fetch(:key_type)
275
- @relationship_type = options.fetch(:relationship_type).to_sym
15
+ def process
16
+ processor.process
276
17
  end
277
18
 
278
- def apply
279
- resource = @resource_klass.find_by_key(@resource_id, context: @context)
280
- result = resource.replace_polymorphic_to_one_link(@relationship_type, @key_value, @key_type)
281
-
282
- return JSONAPI::OperationResult.new(result == :completed ? :no_content : :accepted)
283
- end
284
- end
285
-
286
- class CreateToManyRelationshipOperation < Operation
287
- attr_reader :resource_id, :relationship_type, :data
288
-
289
- def initialize(resource_klass, options)
290
- super(resource_klass, options)
291
- @resource_id = options.fetch(:resource_id)
292
- @data = options.fetch(:data)
293
- @relationship_type = options.fetch(:relationship_type).to_sym
294
- end
295
-
296
- def apply
297
- resource = @resource_klass.find_by_key(@resource_id, context: @context)
298
- result = resource.create_to_many_links(@relationship_type, @data)
299
-
300
- return JSONAPI::OperationResult.new(result == :completed ? :no_content : :accepted)
301
- end
302
- end
303
-
304
- class ReplaceToManyRelationshipOperation < Operation
305
- attr_reader :resource_id, :relationship_type, :data
306
-
307
- def initialize(resource_klass, options)
308
- super(resource_klass, options)
309
- @resource_id = options.fetch(:resource_id)
310
- @data = options.fetch(:data)
311
- @relationship_type = options.fetch(:relationship_type).to_sym
312
- end
313
-
314
- def apply
315
- resource = @resource_klass.find_by_key(@resource_id, context: @context)
316
- result = resource.replace_to_many_links(@relationship_type, @data)
317
-
318
- return JSONAPI::OperationResult.new(result == :completed ? :no_content : :accepted)
319
- end
320
- end
321
-
322
- class RemoveToManyRelationshipOperation < Operation
323
- attr_reader :resource_id, :relationship_type, :associated_key
324
-
325
- def initialize(resource_klass, options)
326
- super(resource_klass, options)
327
- @resource_id = options.fetch(:resource_id)
328
- @associated_key = options.fetch(:associated_key)
329
- @relationship_type = options.fetch(:relationship_type).to_sym
330
- end
331
-
332
- def apply
333
- resource = @resource_klass.find_by_key(@resource_id, context: @context)
334
- result = resource.remove_to_many_link(@relationship_type, @associated_key)
335
-
336
- return JSONAPI::OperationResult.new(result == :completed ? :no_content : :accepted)
337
- end
338
- end
339
-
340
- class RemoveToOneRelationshipOperation < Operation
341
- attr_reader :resource_id, :relationship_type
342
-
343
- def initialize(resource_klass, options)
344
- super(resource_klass, options)
345
- @resource_id = options.fetch(:resource_id)
346
- @relationship_type = options.fetch(:relationship_type).to_sym
347
- end
348
-
349
- def apply
350
- resource = @resource_klass.find_by_key(@resource_id, context: @context)
351
- result = resource.remove_to_one_link(@relationship_type)
352
-
353
- return JSONAPI::OperationResult.new(result == :completed ? :no_content : :accepted)
19
+ private
20
+ def processor
21
+ JSONAPI::Processor.processor_instance_for(resource_klass, operation_type, options)
354
22
  end
355
23
  end
356
24
  end