jsonapi-resources 0.7.1.beta1 → 0.7.1.beta2

Sign up to get free protection for your applications and to get access to all the features.
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