jsonapi-resources 0.5.9 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +2 -3
- data/README.md +101 -32
- data/jsonapi-resources.gemspec +0 -1
- data/lib/jsonapi/acts_as_resource_controller.rb +9 -9
- data/lib/jsonapi/link_builder.rb +1 -1
- data/lib/jsonapi/operation.rb +1 -1
- data/lib/jsonapi/request.rb +58 -65
- data/lib/jsonapi/resource.rb +8 -15
- data/lib/jsonapi/resource_serializer.rb +9 -4
- data/lib/jsonapi/resources/version.rb +1 -1
- data/lib/jsonapi/routing_ext.rb +1 -1
- data/test/config/database.yml +1 -2
- data/test/controllers/controller_test.rb +80 -2
- data/test/fixtures/active_record.rb +59 -10
- data/test/fixtures/companies.yml +4 -0
- data/test/integration/routes/routes_test.rb +2 -2
- data/test/integration/sti_fields_test.rb +18 -0
- data/test/test_helper.rb +7 -1
- data/test/unit/resource/resource_test.rb +30 -17
- data/test/unit/serializer/link_builder_test.rb +8 -8
- data/test/unit/serializer/polymorphic_serializer_test.rb +2 -2
- data/test/unit/serializer/serializer_test.rb +16 -16
- metadata +7 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6f1f659549f6b8804be7a7bed6ca3a359a37fc5e
|
4
|
+
data.tar.gz: 3703986e36f362f348ce463d4977b268171d8f0b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7b368231330b4c2a21bcfde117c7c4797a16c3bf145e20525b6fcdff429fde0a276e2b9b95b0e265dee890f37b4862529e7780f4caef90886d99ea36a4877af5
|
7
|
+
data.tar.gz: 4518564dceb728f5a594dd93c9fcf22de5051ad6397a4282513ad8f8f7d27c7bae355cae3bc8a9fd593fc11bdfdb91885f878a17a809d0150d1ef4daa4a7a174
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# JSONAPI::Resources [![Build Status](https://secure.travis-ci.org/cerebris/jsonapi-resources.png?branch=master)](http://travis-ci.org/cerebris/jsonapi-resources) [![Code Climate](https://codeclimate.com/github/cerebris/jsonapi-resources/badges/gpa.svg)](https://codeclimate.com/github/cerebris/jsonapi-resources)
|
2
2
|
|
3
|
+
[![Join the chat at https://gitter.im/cerebris/jsonapi-resources](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/cerebris/jsonapi-resources?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
4
|
+
|
3
5
|
`JSONAPI::Resources`, or "JR", provides a framework for developing a server that complies with the
|
4
6
|
[JSON API](http://jsonapi.org/) specification.
|
5
7
|
|
@@ -29,6 +31,7 @@ backed by ActiveRecord models or by custom objects.
|
|
29
31
|
* [Namespaces] (#namespaces)
|
30
32
|
* [Error Codes] (#error-codes)
|
31
33
|
* [Handling Exceptions] (#handling-exceptions)
|
34
|
+
* [Action Callbacks] (#action-callbacks)
|
32
35
|
* [Serializer] (#serializer)
|
33
36
|
* [Configuration] (#configuration)
|
34
37
|
* [Contributing] (#contributing)
|
@@ -150,7 +153,7 @@ class AuthorResource < JSONAPI::Resource
|
|
150
153
|
has_many :posts
|
151
154
|
|
152
155
|
def fetchable_fields
|
153
|
-
if (context
|
156
|
+
if (context[:current_user].guest)
|
154
157
|
super - [:email]
|
155
158
|
else
|
156
159
|
super
|
@@ -225,6 +228,41 @@ end
|
|
225
228
|
The system will lookup a value formatter named `DateWithTimezoneValueFormatter` and will use this when serializing and
|
226
229
|
updating the attribute. See the [Value Formatters](#value-formatters) section for more details.
|
227
230
|
|
231
|
+
##### Flattening a Rails relationship
|
232
|
+
|
233
|
+
It is possible to flatten Rails relationships into attributes by using getters and setters. This can become handy if a relation needs to be created alongside the creation of the main object which can be the case if there is a bi-directional presence validation. For example:
|
234
|
+
|
235
|
+
```ruby
|
236
|
+
# Given Models
|
237
|
+
class Person < ActiveRecord::Base
|
238
|
+
has_many :spoken_languages
|
239
|
+
validates :name, :email, :spoken_languages, presence: true
|
240
|
+
end
|
241
|
+
|
242
|
+
class SpokenLanguage < ActiveRecord::Base
|
243
|
+
belongs_to :person, inverse_of: :spoken_languages
|
244
|
+
validates :person, :language_code, presence: true
|
245
|
+
end
|
246
|
+
|
247
|
+
# Resource with getters and setter
|
248
|
+
class PersonResource < JSONAPI::Resource
|
249
|
+
attributes :name, :email, :spoken_languages
|
250
|
+
|
251
|
+
# Getter
|
252
|
+
def spoken_languages
|
253
|
+
@model.spoken_languages.pluck(:language_code)
|
254
|
+
end
|
255
|
+
|
256
|
+
# Setter (because spoken_languages needed for creation)
|
257
|
+
def spoken_languages=(new_spoken_language_codes)
|
258
|
+
@model.spoken_languages.destroy_all
|
259
|
+
new_spoken_language_codes.each do |new_lang_code|
|
260
|
+
@model.spoken_languages.build(language_code: new_lang_code)
|
261
|
+
end
|
262
|
+
end
|
263
|
+
end
|
264
|
+
```
|
265
|
+
|
228
266
|
#### Primary Key
|
229
267
|
|
230
268
|
Resources are always represented using a key of `id`. The resource will interrogate the model to find the primary key.
|
@@ -445,25 +483,27 @@ class PostResource < JSONAPI::Resource
|
|
445
483
|
|
446
484
|
def self.records(options = {})
|
447
485
|
context = options[:context]
|
448
|
-
context
|
486
|
+
context[:current_user].posts
|
449
487
|
end
|
450
488
|
end
|
451
489
|
```
|
452
490
|
|
453
|
-
When you create a relationship, a method is created to fetch record(s) for that relationship
|
454
|
-
|
491
|
+
When you create a relationship, a method is created to fetch record(s) for that relationship, using the relation name
|
492
|
+
for the relationship.
|
455
493
|
|
456
494
|
```ruby
|
457
495
|
class PostResource < JSONAPI::Resource
|
458
496
|
has_one :author
|
459
497
|
has_many :comments
|
460
498
|
|
461
|
-
# def record_for_author
|
462
|
-
#
|
499
|
+
# def record_for_author
|
500
|
+
# relation_name = relationship.relation_name(context: @context)
|
501
|
+
# records_for(relation_name)
|
463
502
|
# end
|
464
503
|
|
465
|
-
# def records_for_comments
|
466
|
-
#
|
504
|
+
# def records_for_comments
|
505
|
+
# relation_name = relationship.relation_name(context: @context)
|
506
|
+
# records_for(relation_name)
|
467
507
|
# end
|
468
508
|
end
|
469
509
|
|
@@ -474,11 +514,11 @@ section for additional details on raising errors.
|
|
474
514
|
|
475
515
|
```ruby
|
476
516
|
class BaseResource < JSONAPI::Resource
|
477
|
-
def records_for(
|
517
|
+
def records_for(relation_name)
|
478
518
|
context = options[:context]
|
479
|
-
records = model.public_send(
|
519
|
+
records = model.public_send(relation_name)
|
480
520
|
|
481
|
-
unless context
|
521
|
+
unless context[:current_user].can_view?(records)
|
482
522
|
raise NotAuthorizedError
|
483
523
|
end
|
484
524
|
|
@@ -567,10 +607,10 @@ class AuthorResource < JSONAPI::Resource
|
|
567
607
|
|
568
608
|
def self.find(filters, options = {})
|
569
609
|
context = options[:context]
|
570
|
-
authors = context
|
610
|
+
authors = context[:current_user].find_authors(filters)
|
571
611
|
|
572
612
|
return authors.map do |author|
|
573
|
-
self.new(author)
|
613
|
+
self.new(author, context)
|
574
614
|
end
|
575
615
|
end
|
576
616
|
end
|
@@ -626,7 +666,7 @@ The default paginator, which will be used for all resources, is set using `JSONA
|
|
626
666
|
|
627
667
|
```ruby
|
628
668
|
JSONAPI.configure do |config|
|
629
|
-
# built in paginators are :none, :offset, :
|
669
|
+
# built in paginators are :none, :offset, :paged
|
630
670
|
config.default_paginator = :offset
|
631
671
|
|
632
672
|
config.default_page_size = 10
|
@@ -709,8 +749,6 @@ Will get you the following payload by default:
|
|
709
749
|
}
|
710
750
|
```
|
711
751
|
|
712
|
-
You can also pass an `include` option to [Serializer#serialize_to_hash](#include) if you want to define this inline.
|
713
|
-
|
714
752
|
#### Callbacks
|
715
753
|
|
716
754
|
`ActiveSupport::Callbacks` is used to provide callback functionality, so the behavior is very similar to what you may be
|
@@ -781,6 +819,7 @@ To return the total record count of a find operation in the meta data of a find
|
|
781
819
|
OperationsProcessor. For example:
|
782
820
|
|
783
821
|
```ruby
|
822
|
+
# lib/jsonapi/counting_active_record_operations_processor.rb
|
784
823
|
class CountingActiveRecordOperationsProcessor < ActiveRecordOperationsProcessor
|
785
824
|
after_find_operation do
|
786
825
|
@operation_meta[:total_records] = @operation.record_count
|
@@ -792,6 +831,8 @@ Set the configuration option `operations_processor` to use the new `CountingActi
|
|
792
831
|
specifying the snake cased name of the class (without the `OperationsProcessor`).
|
793
832
|
|
794
833
|
```ruby
|
834
|
+
require 'jsonapi/counting_active_record_operations_processor'
|
835
|
+
|
795
836
|
JSONAPI.configure do |config|
|
796
837
|
config.operations_processor = :counting_active_record
|
797
838
|
end
|
@@ -840,6 +881,8 @@ class PeopleController < ApplicationController
|
|
840
881
|
end
|
841
882
|
```
|
842
883
|
|
884
|
+
> __Note__: This gem [uses the filter chain to set up the request](https://github.com/cerebris/jsonapi-resources/issues/458#issuecomment-143297055). In some instances, variables that are set in the filter chain (such as `current_user`) may not be set at the right time. If this happens (i.e. `current_user` is `nil` in `context` but it's set properly everywhere else), you may want to have your authentication occur earlier in the filter chain, using `prepend_before_action` instead of `before_action`.
|
885
|
+
|
843
886
|
##### ActsAsResourceController
|
844
887
|
|
845
888
|
`JSONAPI::Resources` also provides a module, `JSONAPI::ActsAsResourceController`. You can include this module to
|
@@ -994,12 +1037,12 @@ end
|
|
994
1037
|
|
995
1038
|
By default, all exceptions raised downstream from a resource controller will be caught, logged, and a ```500 Internal Server Error``` will be rendered. Exceptions can be whitelisted in the config to pass through the handler and be caught manually, or you can pass a callback from a resource controller to insert logic into the rescue block without interrupting the control flow. This can be particularly useful for additional logging or monitoring without the added work of rendering responses.
|
996
1039
|
|
997
|
-
Pass a block, refer to controller class methods, or both. Note that methods must be defined as class methods on a controller and accept one parameter, which is passed the exception object that was rescued.
|
1040
|
+
Pass a block, refer to controller class methods, or both. Note that methods must be defined as class methods on a controller and accept one parameter, which is passed the exception object that was rescued.
|
998
1041
|
|
999
1042
|
```ruby
|
1000
1043
|
class ApplicationController < JSONAPI::ResourceController
|
1001
1044
|
|
1002
|
-
on_server_error :first_callback
|
1045
|
+
on_server_error :first_callback
|
1003
1046
|
|
1004
1047
|
#or
|
1005
1048
|
|
@@ -1014,6 +1057,26 @@ Pass a block, refer to controller class methods, or both. Note that methods must
|
|
1014
1057
|
|
1015
1058
|
```
|
1016
1059
|
|
1060
|
+
#### Action Callbacks
|
1061
|
+
|
1062
|
+
##### ensure_correct_media_type
|
1063
|
+
|
1064
|
+
By default, when controllers extend functionalities from `jsonapi-resources`, the `ActsAsResourceController#ensure_correct_media_type`
|
1065
|
+
method will be triggered before `create`, `update`, `create_relationship` and `update_relationship` actions. This method is reponsible
|
1066
|
+
for checking if client's request corresponds to the correct media type required by [JSON API](http://jsonapi.org/format/#content-negotiation-clients): `application/vnd.api+json`.
|
1067
|
+
|
1068
|
+
In case you need to check the media type for custom actions, just make sure to call the method in your controller's `before_action`:
|
1069
|
+
|
1070
|
+
```ruby
|
1071
|
+
class UsersController < JSONAPI::ResourceController
|
1072
|
+
before_action :ensure_correct_media_type, only: [:auth]
|
1073
|
+
|
1074
|
+
def auth
|
1075
|
+
# some crazy auth code goes here
|
1076
|
+
end
|
1077
|
+
end
|
1078
|
+
```
|
1079
|
+
|
1017
1080
|
### Serializer
|
1018
1081
|
|
1019
1082
|
The `ResourceSerializer` can be used to serialize a resource into JSON API compliant JSON. `ResourceSerializer` must be
|
@@ -1022,7 +1085,7 @@ The `ResourceSerializer` can be used to serialize a resource into JSON API compl
|
|
1022
1085
|
|
1023
1086
|
```ruby
|
1024
1087
|
post = Post.find(1)
|
1025
|
-
JSONAPI::ResourceSerializer.new(PostResource).serialize_to_hash(PostResource.new(post))
|
1088
|
+
JSONAPI::ResourceSerializer.new(PostResource).serialize_to_hash(PostResource.new(post, nil))
|
1026
1089
|
```
|
1027
1090
|
|
1028
1091
|
This returns results like this:
|
@@ -1075,9 +1138,9 @@ This returns results like this:
|
|
1075
1138
|
}
|
1076
1139
|
```
|
1077
1140
|
|
1078
|
-
####
|
1141
|
+
#### Serializer options
|
1079
1142
|
|
1080
|
-
The `
|
1143
|
+
The `ResourceSerializer` can be initialized with some optional parameters:
|
1081
1144
|
|
1082
1145
|
##### `include`
|
1083
1146
|
|
@@ -1107,13 +1170,9 @@ JSONAPI::ResourceSerializer.new(PostResource, include: include_resources,
|
|
1107
1170
|
tags: [:name],
|
1108
1171
|
comments: [:body, :post]
|
1109
1172
|
}
|
1110
|
-
).serialize_to_hash(PostResource.new(post))
|
1173
|
+
).serialize_to_hash(PostResource.new(post, nil))
|
1111
1174
|
```
|
1112
1175
|
|
1113
|
-
##### `context`
|
1114
|
-
|
1115
|
-
Context data can be provided to the serializer, which passes it to each resource as it is inspected.
|
1116
|
-
|
1117
1176
|
#### Routing
|
1118
1177
|
|
1119
1178
|
JR has a couple of helper methods available to assist you with setting up routes.
|
@@ -1283,18 +1342,23 @@ phone_number_contact GET /phone-numbers/:phone_number_id/contact(.:format) co
|
|
1283
1342
|
|
1284
1343
|
#### Formatting
|
1285
1344
|
|
1286
|
-
JR by default uses some simple rules to format an attribute for serialization. Strings and Integers are output to JSON
|
1345
|
+
JR by default uses some simple rules to format (and unformat) an attribute for (de-)serialization. Strings and Integers are output to JSON
|
1287
1346
|
as is, and all other values have `.to_s` applied to them. This outputs something in all cases, but it is certainly not
|
1288
1347
|
correct for every situation.
|
1289
1348
|
|
1290
|
-
If you want to change the way an attribute is serialized you have a couple of ways. The simplest method is to create a
|
1291
|
-
getter method on the resource which overrides the attribute and apply the formatting there. For example:
|
1349
|
+
If you want to change the way an attribute is (de-)serialized you have a couple of ways. The simplest method is to create a
|
1350
|
+
getter (and setter) method on the resource which overrides the attribute and apply the (un-)formatting there. For example:
|
1292
1351
|
|
1293
1352
|
```ruby
|
1294
1353
|
class PersonResource < JSONAPI::Resource
|
1295
|
-
attributes :name, :email
|
1296
|
-
attribute :last_login_time
|
1354
|
+
attributes :name, :email, :last_login_time
|
1297
1355
|
|
1356
|
+
# Setter example
|
1357
|
+
def email=(new_email)
|
1358
|
+
@model.email = new_email.downcase
|
1359
|
+
end
|
1360
|
+
|
1361
|
+
# Getter example
|
1298
1362
|
def last_login_time
|
1299
1363
|
@model.last_login_time.in_time_zone(@context[:current_user].time_zone).to_s
|
1300
1364
|
end
|
@@ -1312,8 +1376,10 @@ handled for an attribute. The `format` can be set per attribute as it is declare
|
|
1312
1376
|
|
1313
1377
|
```ruby
|
1314
1378
|
class PersonResource < JSONAPI::Resource
|
1315
|
-
attributes :name, :email
|
1379
|
+
attributes :name, :email, :spoken_languages
|
1316
1380
|
attribute :last_login_time, format: :date_with_utc_timezone
|
1381
|
+
|
1382
|
+
# Getter/Setter for spoken_languages ...
|
1317
1383
|
end
|
1318
1384
|
```
|
1319
1385
|
|
@@ -1431,6 +1497,9 @@ JR has a few configuration options. Some have already been mentioned above. To s
|
|
1431
1497
|
initializer and add the options you wish to set. All options have defaults, so you only need to set the options that
|
1432
1498
|
are different. The default options are shown below.
|
1433
1499
|
|
1500
|
+
If using custom classes (such as the CountingActiveRecordOperationsProcessor, or a CustomPaginator),
|
1501
|
+
be sure to require them at the top of the initializer before usage.
|
1502
|
+
|
1434
1503
|
```ruby
|
1435
1504
|
JSONAPI.configure do |config|
|
1436
1505
|
#:underscored_key, :camelized_key, :dasherized_key, or custom
|
data/jsonapi-resources.gemspec
CHANGED
@@ -23,7 +23,6 @@ Gem::Specification.new do |spec|
|
|
23
23
|
spec.add_development_dependency 'rake'
|
24
24
|
spec.add_development_dependency 'minitest'
|
25
25
|
spec.add_development_dependency 'minitest-spec-rails'
|
26
|
-
spec.add_development_dependency 'minitest-reporters'
|
27
26
|
spec.add_development_dependency 'simplecov'
|
28
27
|
spec.add_development_dependency 'pry'
|
29
28
|
spec.add_dependency 'rails', '>= 4.0'
|
@@ -5,9 +5,9 @@ module JSONAPI
|
|
5
5
|
extend ActiveSupport::Concern
|
6
6
|
|
7
7
|
included do
|
8
|
-
|
9
|
-
|
10
|
-
|
8
|
+
before_action :ensure_correct_media_type, only: [:create, :update, :create_relationship, :update_relationship]
|
9
|
+
append_before_action :setup_request
|
10
|
+
after_action :setup_response
|
11
11
|
end
|
12
12
|
|
13
13
|
def index
|
@@ -187,22 +187,22 @@ module JSONAPI
|
|
187
187
|
@request.server_error_callbacks = callbacks || []
|
188
188
|
end
|
189
189
|
|
190
|
-
# Pass in a methods or a block to be run when an exception is
|
190
|
+
# Pass in a methods or a block to be run when an exception is
|
191
191
|
# caught that is not a JSONAPI::Exceptions::Error
|
192
|
-
# Useful for additional logging or notification configuration that
|
192
|
+
# Useful for additional logging or notification configuration that
|
193
193
|
# would normally depend on rails catching and rendering an exception.
|
194
194
|
# Ignores whitelist exceptions from config
|
195
195
|
|
196
|
-
|
196
|
+
module ClassMethods
|
197
197
|
def on_server_error(*args, &callback_block)
|
198
198
|
callbacks = []
|
199
199
|
|
200
|
-
if callback_block
|
200
|
+
if callback_block
|
201
201
|
callbacks << callback_block
|
202
202
|
end
|
203
203
|
|
204
204
|
method_callbacks = args.map do |method|
|
205
|
-
->(error) do
|
205
|
+
->(error) do
|
206
206
|
if self.respond_to? method
|
207
207
|
send(method, error)
|
208
208
|
else
|
@@ -211,7 +211,7 @@ module JSONAPI
|
|
211
211
|
end
|
212
212
|
end.compact
|
213
213
|
callbacks += method_callbacks
|
214
|
-
|
214
|
+
append_before_action { add_error_callbacks(callbacks) }
|
215
215
|
end
|
216
216
|
end
|
217
217
|
end
|
data/lib/jsonapi/link_builder.rb
CHANGED
@@ -81,7 +81,7 @@ module JSONAPI
|
|
81
81
|
scopes = module_scopes_from_class(source.class)[1..-1]
|
82
82
|
base_path_name = scopes.map { |scope| scope.underscore }.join("_")
|
83
83
|
end_path_name = source.class._type.to_s.singularize
|
84
|
-
|
84
|
+
[base_path_name, end_path_name, "path"].reject(&:blank?).join("_")
|
85
85
|
end
|
86
86
|
|
87
87
|
def engine_resource_url(source)
|
data/lib/jsonapi/operation.rb
CHANGED
data/lib/jsonapi/request.rb
CHANGED
@@ -92,15 +92,11 @@ module JSONAPI
|
|
92
92
|
end
|
93
93
|
|
94
94
|
def setup_create_relationship_action(params)
|
95
|
-
|
96
|
-
params.require(:relationship),
|
97
|
-
params.require(@resource_klass._as_parent_key))
|
95
|
+
parse_modify_relationship_action(params, :add)
|
98
96
|
end
|
99
97
|
|
100
98
|
def setup_update_relationship_action(params)
|
101
|
-
|
102
|
-
params.require(:relationship),
|
103
|
-
params.require(@resource_klass._as_parent_key))
|
99
|
+
parse_modify_relationship_action(params, :update)
|
104
100
|
end
|
105
101
|
|
106
102
|
def setup_update_action(params)
|
@@ -114,7 +110,28 @@ module JSONAPI
|
|
114
110
|
end
|
115
111
|
|
116
112
|
def setup_destroy_relationship_action(params)
|
117
|
-
|
113
|
+
parse_modify_relationship_action(params, :remove)
|
114
|
+
end
|
115
|
+
|
116
|
+
def parse_modify_relationship_action(params, modification_type)
|
117
|
+
relationship_type = params.require(:relationship)
|
118
|
+
parent_key = params.require(@resource_klass._as_parent_key)
|
119
|
+
relationship = @resource_klass._relationship(relationship_type)
|
120
|
+
|
121
|
+
# Removals of to-one relationships are done implicitly and require no specification of data
|
122
|
+
data_required = !(modification_type == :remove && relationship.is_a?(JSONAPI::Relationship::ToOne))
|
123
|
+
|
124
|
+
if data_required
|
125
|
+
data = params.fetch(:data)
|
126
|
+
object_params = { relationships: { format_key(relationship.name) => { data: data } } }
|
127
|
+
verified_params = parse_params(object_params, updatable_fields)
|
128
|
+
|
129
|
+
parse_arguments = [verified_params, relationship, parent_key]
|
130
|
+
else
|
131
|
+
parse_arguments = [params, relationship, parent_key]
|
132
|
+
end
|
133
|
+
|
134
|
+
send(:"parse_#{modification_type}_relationship_operation", *parse_arguments)
|
118
135
|
end
|
119
136
|
|
120
137
|
def initialize_source(params)
|
@@ -159,8 +176,7 @@ module JSONAPI
|
|
159
176
|
@errors.concat(e.errors)
|
160
177
|
end
|
161
178
|
|
162
|
-
if type_resource.nil?
|
163
|
-
@resource_klass._has_relationship?(underscored_type))
|
179
|
+
if type_resource.nil?
|
164
180
|
@errors.concat(JSONAPI::Exceptions::InvalidResource.new(type).errors)
|
165
181
|
else
|
166
182
|
unless values.nil?
|
@@ -548,66 +564,47 @@ module JSONAPI
|
|
548
564
|
end
|
549
565
|
# :nocov:
|
550
566
|
|
551
|
-
def parse_add_relationship_operation(
|
552
|
-
relationship = resource_klass._relationship(relationship_type)
|
553
|
-
|
567
|
+
def parse_add_relationship_operation(verified_params, relationship, parent_key)
|
554
568
|
if relationship.is_a?(JSONAPI::Relationship::ToMany)
|
555
|
-
object_params = { relationships: { format_key(relationship.name) => { data: data } } }
|
556
|
-
verified_param_set = parse_params(object_params, updatable_fields)
|
557
|
-
|
558
569
|
@operations.push JSONAPI::CreateToManyRelationshipOperation.new(
|
559
570
|
resource_klass,
|
560
571
|
context: @context,
|
561
572
|
resource_id: parent_key,
|
562
|
-
relationship_type:
|
563
|
-
data:
|
573
|
+
relationship_type: relationship.name,
|
574
|
+
data: verified_params[:to_many].values[0]
|
564
575
|
)
|
565
576
|
end
|
566
577
|
end
|
567
578
|
|
568
|
-
def parse_update_relationship_operation(
|
569
|
-
|
579
|
+
def parse_update_relationship_operation(verified_params, relationship, parent_key)
|
580
|
+
operation_args = [resource_klass].push(
|
581
|
+
context: @context,
|
582
|
+
resource_id: parent_key,
|
583
|
+
relationship_type: relationship.name
|
584
|
+
)
|
585
|
+
|
570
586
|
if relationship.is_a?(JSONAPI::Relationship::ToOne)
|
571
587
|
if relationship.polymorphic?
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
resource_id: parent_key,
|
579
|
-
relationship_type: relationship_type,
|
580
|
-
key_value: verified_param_set[:to_one].values[0][:id],
|
581
|
-
key_type: verified_param_set[:to_one].values[0][:type]
|
582
|
-
)
|
588
|
+
operation_args[1].merge!(
|
589
|
+
key_value: verified_params[:to_one].values[0][:id],
|
590
|
+
key_type: verified_params[:to_one].values[0][:type]
|
591
|
+
)
|
592
|
+
|
593
|
+
operation_klass = JSONAPI::ReplacePolymorphicToOneRelationshipOperation
|
583
594
|
else
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
@operations.push JSONAPI::ReplaceToOneRelationshipOperation.new(
|
588
|
-
resource_klass,
|
589
|
-
context: @context,
|
590
|
-
resource_id: parent_key,
|
591
|
-
relationship_type: relationship_type,
|
592
|
-
key_value: verified_param_set[:to_one].values[0]
|
593
|
-
)
|
595
|
+
operation_args[1].merge!(key_value: verified_params[:to_one].values[0])
|
596
|
+
operation_klass = JSONAPI::ReplaceToOneRelationshipOperation
|
594
597
|
end
|
595
598
|
elsif relationship.is_a?(JSONAPI::Relationship::ToMany)
|
596
599
|
unless relationship.acts_as_set
|
597
600
|
fail JSONAPI::Exceptions::ToManySetReplacementForbidden.new
|
598
601
|
end
|
599
602
|
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
@operations.push JSONAPI::ReplaceToManyRelationshipOperation.new(
|
604
|
-
resource_klass,
|
605
|
-
context: @context,
|
606
|
-
resource_id: parent_key,
|
607
|
-
relationship_type: relationship_type,
|
608
|
-
data: verified_param_set[:to_many].values[0]
|
609
|
-
)
|
603
|
+
operation_args[1].merge!(data: verified_params[:to_many].values[0])
|
604
|
+
operation_klass = JSONAPI::ReplaceToManyRelationshipOperation
|
610
605
|
end
|
606
|
+
|
607
|
+
@operations.push(operation_klass.send(:new, *operation_args))
|
611
608
|
end
|
612
609
|
|
613
610
|
def parse_single_replace_operation(data, keys, id_key_presence_check_required: true)
|
@@ -665,29 +662,25 @@ module JSONAPI
|
|
665
662
|
@errors.concat(e.errors)
|
666
663
|
end
|
667
664
|
|
668
|
-
def parse_remove_relationship_operation(params)
|
669
|
-
|
670
|
-
|
671
|
-
|
665
|
+
def parse_remove_relationship_operation(params, relationship, parent_key)
|
666
|
+
operation_base_args = [resource_klass].push(
|
667
|
+
context: @context,
|
668
|
+
resource_id: parent_key,
|
669
|
+
relationship_type: relationship.name
|
670
|
+
)
|
672
671
|
|
673
|
-
relationship = resource_klass._relationship(relationship_type)
|
674
672
|
if relationship.is_a?(JSONAPI::Relationship::ToMany)
|
675
|
-
keys =
|
673
|
+
keys = params[:to_many].values[0]
|
676
674
|
keys.each do |key|
|
675
|
+
operation_args = operation_base_args.dup
|
676
|
+
operation_args[1] = operation_args[1].merge(associated_key: key)
|
677
677
|
@operations.push JSONAPI::RemoveToManyRelationshipOperation.new(
|
678
|
-
|
679
|
-
context: @context,
|
680
|
-
resource_id: parent_key,
|
681
|
-
relationship_type: relationship_type,
|
682
|
-
associated_key: key
|
678
|
+
*operation_args
|
683
679
|
)
|
684
680
|
end
|
685
681
|
else
|
686
682
|
@operations.push JSONAPI::RemoveToOneRelationshipOperation.new(
|
687
|
-
|
688
|
-
context: @context,
|
689
|
-
resource_id: parent_key,
|
690
|
-
relationship_type: relationship_type
|
683
|
+
*operation_base_args
|
691
684
|
)
|
692
685
|
end
|
693
686
|
end
|