jsonapi-resources 0.3.0.pre2 → 0.3.0
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.
- checksums.yaml +4 -4
- data/README.md +132 -29
- data/lib/jsonapi/association.rb +2 -1
- data/lib/jsonapi/error_codes.rb +1 -0
- data/lib/jsonapi/exceptions.rb +9 -0
- data/lib/jsonapi/request.rb +6 -2
- data/lib/jsonapi/resource.rb +3 -9
- data/lib/jsonapi/resource_controller.rb +21 -29
- data/lib/jsonapi/resource_serializer.rb +2 -0
- data/lib/jsonapi/resources/version.rb +1 -1
- data/lib/jsonapi/routing_ext.rb +1 -1
- data/test/controllers/controller_test.rb +17 -1
- data/test/fixtures/comments.yml +5 -1
- data/test/integration/requests/request_test.rb +26 -1
- data/test/test_helper.rb +0 -1
- data/test/unit/serializer/serializer_test.rb +12 -23
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7f8dd7b98dfa7f20a9b75456fd8ca066ae807fd0
|
4
|
+
data.tar.gz: 4aaa07053a74089ef0880f4154e79261a97529d9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 06358dd197a8efa202d8c3b82493be75c5bb65d22338dd78bf56b3475093879ee93703ea99c450d377962ec0dcfe4ff9165c52ce0cac2157be59b45722b121f0
|
7
|
+
data.tar.gz: 077d88d176ed150fe694fc105f57f0092526139b628ab9c7bb3b38d37c6e8b14ce367ccee4ccac4cbbcf8da57f6e606b658e65c8fabec7b5b629f534790a4bae
|
data/README.md
CHANGED
@@ -709,12 +709,11 @@ JR has a couple of helper methods available to assist you with setting up routes
|
|
709
709
|
|
710
710
|
##### `jsonapi_resources`
|
711
711
|
|
712
|
-
Like `resources` in `ActionDispatch`, `jsonapi_resources` provides resourceful routes mapping between HTTP verbs and URLs
|
712
|
+
Like `resources` in `ActionDispatch`, `jsonapi_resources` provides resourceful routes mapping between HTTP verbs and URLs
|
713
|
+
and controller actions. This will also setup mappings for relationship URLs for a resource's associations. For example:
|
713
714
|
|
714
715
|
```ruby
|
715
|
-
|
716
|
-
|
717
|
-
Peeps::Application.routes.draw do
|
716
|
+
Rails.application.routes.draw do
|
718
717
|
jsonapi_resources :contacts
|
719
718
|
jsonapi_resources :phone_numbers
|
720
719
|
end
|
@@ -723,10 +722,85 @@ end
|
|
723
722
|
gives the following routes
|
724
723
|
|
725
724
|
```
|
726
|
-
Prefix Verb
|
727
|
-
contact_links_phone_numbers GET
|
728
|
-
POST
|
729
|
-
DELETE
|
725
|
+
Prefix Verb URI Pattern Controller#Action
|
726
|
+
contact_links_phone_numbers GET /contacts/:contact_id/links/phone-numbers(.:format) contacts#show_association {:association=>"phone_numbers"}
|
727
|
+
POST /contacts/:contact_id/links/phone-numbers(.:format) contacts#create_association {:association=>"phone_numbers"}
|
728
|
+
DELETE /contacts/:contact_id/links/phone-numbers/:keys(.:format) contacts#destroy_association {:association=>"phone_numbers"}
|
729
|
+
contact_phone_numbers GET /contacts/:contact_id/phone-numbers(.:format) phone_numbers#get_related_resources {:association=>"phone_numbers", :source=>"contacts"}
|
730
|
+
contacts GET /contacts(.:format) contacts#index
|
731
|
+
POST /contacts(.:format) contacts#create
|
732
|
+
new_contact GET /contacts/new(.:format) contacts#new
|
733
|
+
edit_contact GET /contacts/:id/edit(.:format) contacts#edit
|
734
|
+
contact GET /contacts/:id(.:format) contacts#show
|
735
|
+
PATCH /contacts/:id(.:format) contacts#update
|
736
|
+
PUT /contacts/:id(.:format) contacts#update
|
737
|
+
DELETE /contacts/:id(.:format) contacts#destroy
|
738
|
+
phone_number_links_contact GET /phone-numbers/:phone_number_id/links/contact(.:format) phone_numbers#show_association {:association=>"contact"}
|
739
|
+
PUT|PATCH /phone-numbers/:phone_number_id/links/contact(.:format) phone_numbers#update_association {:association=>"contact"}
|
740
|
+
DELETE /phone-numbers/:phone_number_id/links/contact(.:format) phone_numbers#destroy_association {:association=>"contact"}
|
741
|
+
phone_number_contact GET /phone-numbers/:phone_number_id/contact(.:format) contacts#get_related_resource {:association=>"contact", :source=>"phone_numbers"}
|
742
|
+
phone_numbers GET /phone-numbers(.:format) phone_numbers#index
|
743
|
+
POST /phone-numbers(.:format) phone_numbers#create
|
744
|
+
new_phone_number GET /phone-numbers/new(.:format) phone_numbers#new
|
745
|
+
edit_phone_number GET /phone-numbers/:id/edit(.:format) phone_numbers#edit
|
746
|
+
phone_number GET /phone-numbers/:id(.:format) phone_numbers#show
|
747
|
+
PATCH /phone-numbers/:id(.:format) phone_numbers#update
|
748
|
+
PUT /phone-numbers/:id(.:format) phone_numbers#update
|
749
|
+
DELETE /phone-numbers/:id(.:format) phone_numbers#destroy
|
750
|
+
```
|
751
|
+
|
752
|
+
##### `jsonapi_resource`
|
753
|
+
|
754
|
+
Like `jsonapi_resources`, but for resources you lookup without an id.
|
755
|
+
|
756
|
+
#### Nested Routes
|
757
|
+
|
758
|
+
By default nested routes are created for getting related resources and manipulating relationships. You can control the
|
759
|
+
nested routes by passing a block into `jsonapi_resources` or `jsonapi_resource`. An empty block will not create
|
760
|
+
any nested routes. For example:
|
761
|
+
|
762
|
+
```ruby
|
763
|
+
Rails.application.routes.draw do
|
764
|
+
jsonapi_resources :contacts do
|
765
|
+
end
|
766
|
+
end
|
767
|
+
```
|
768
|
+
|
769
|
+
gives routes that are only related to the primary resource, and none for its relationships:
|
770
|
+
|
771
|
+
```
|
772
|
+
Prefix Verb URI Pattern Controller#Action
|
773
|
+
contacts GET /contacts(.:format) contacts#index
|
774
|
+
POST /contacts(.:format) contacts#create
|
775
|
+
new_contact GET /contacts/new(.:format) contacts#new
|
776
|
+
edit_contact GET /contacts/:id/edit(.:format) contacts#edit
|
777
|
+
contact GET /contacts/:id(.:format) contacts#show
|
778
|
+
PATCH /contacts/:id(.:format) contacts#update
|
779
|
+
PUT /contacts/:id(.:format) contacts#update
|
780
|
+
DELETE /contacts/:id(.:format) contacts#destroy
|
781
|
+
```
|
782
|
+
|
783
|
+
To manually add in the nested routes you can use the `jsonapi_links`, `jsonapi_related_resources` and
|
784
|
+
`jsonapi_related_resource` inside the block.
|
785
|
+
|
786
|
+
###### `jsonapi_links`
|
787
|
+
|
788
|
+
You can add relationship routes in with `jsonapi_links`, for example:
|
789
|
+
|
790
|
+
```ruby
|
791
|
+
Rails.application.routes.draw do
|
792
|
+
jsonapi_resources :contacts do
|
793
|
+
jsonapi_links :phone_numbers
|
794
|
+
end
|
795
|
+
end
|
796
|
+
```
|
797
|
+
|
798
|
+
Gives the following routes:
|
799
|
+
|
800
|
+
```
|
801
|
+
contact_links_phone_numbers GET /contacts/:contact_id/links/phone-numbers(.:format) contacts#show_association {:association=>"phone_numbers"}
|
802
|
+
POST /contacts/:contact_id/links/phone-numbers(.:format) contacts#create_association {:association=>"phone_numbers"}
|
803
|
+
DELETE /contacts/:contact_id/links/phone-numbers/:keys(.:format) contacts#destroy_association {:association=>"phone_numbers"}
|
730
804
|
contacts GET /contacts(.:format) contacts#index
|
731
805
|
POST /contacts(.:format) contacts#create
|
732
806
|
new_contact GET /contacts/new(.:format) contacts#new
|
@@ -735,40 +809,69 @@ contact_links_phone_numbers GET /contacts/:contact_id/links/phone_numbers(.:f
|
|
735
809
|
PATCH /contacts/:id(.:format) contacts#update
|
736
810
|
PUT /contacts/:id(.:format) contacts#update
|
737
811
|
DELETE /contacts/:id(.:format) contacts#destroy
|
738
|
-
|
739
|
-
POST /phone_numbers/:phone_number_id/links/contact(.:format) phone_numbers#create_association {:association=>"contact"}
|
740
|
-
DELETE /phone_numbers/:phone_number_id/links/contact(.:format) phone_numbers#destroy_association {:association=>"contact"}
|
741
|
-
phone_numbers GET /phone_numbers(.:format) phone_numbers#index
|
742
|
-
POST /phone_numbers(.:format) phone_numbers#create
|
743
|
-
new_phone_number GET /phone_numbers/new(.:format) phone_numbers#new
|
744
|
-
edit_phone_number GET /phone_numbers/:id/edit(.:format) phone_numbers#edit
|
745
|
-
phone_number GET /phone_numbers/:id(.:format) phone_numbers#show
|
746
|
-
PATCH /phone_numbers/:id(.:format) phone_numbers#update
|
747
|
-
PUT /phone_numbers/:id(.:format) phone_numbers#update
|
748
|
-
DELETE /phone_numbers/:id(.:format) phone_numbers#destroy
|
812
|
+
|
749
813
|
```
|
750
814
|
|
751
|
-
|
815
|
+
The new routes allow you to show, create and destroy the associations between resources.
|
752
816
|
|
753
|
-
|
817
|
+
###### `jsonapi_related_resources`
|
754
818
|
|
755
|
-
|
819
|
+
Creates a nested route to GET the related has_many resources. For example:
|
756
820
|
|
757
|
-
|
758
|
-
|
821
|
+
```ruby
|
822
|
+
Rails.application.routes.draw do
|
823
|
+
jsonapi_resources :contacts do
|
824
|
+
jsonapi_related_resources :phone_numbers
|
825
|
+
end
|
826
|
+
end
|
759
827
|
|
760
|
-
|
828
|
+
```
|
829
|
+
|
830
|
+
gives the following routes:
|
831
|
+
|
832
|
+
```
|
833
|
+
Prefix Verb URI Pattern Controller#Action
|
834
|
+
contact_phone_numbers GET /contacts/:contact_id/phone-numbers(.:format) phone_numbers#get_related_resources {:association=>"phone_numbers", :source=>"contacts"}
|
835
|
+
contacts GET /contacts(.:format) contacts#index
|
836
|
+
POST /contacts(.:format) contacts#create
|
837
|
+
new_contact GET /contacts/new(.:format) contacts#new
|
838
|
+
edit_contact GET /contacts/:id/edit(.:format) contacts#edit
|
839
|
+
contact GET /contacts/:id(.:format) contacts#show
|
840
|
+
PATCH /contacts/:id(.:format) contacts#update
|
841
|
+
PUT /contacts/:id(.:format) contacts#update
|
842
|
+
DELETE /contacts/:id(.:format) contacts#destroy
|
843
|
+
|
844
|
+
```
|
845
|
+
|
846
|
+
A single additional route was created to allow you GET the phone numbers through the contact.
|
847
|
+
|
848
|
+
###### `jsonapi_related_resource`
|
849
|
+
|
850
|
+
Like `jsonapi_related_resources`, but for has_one related resources.
|
761
851
|
|
762
852
|
```ruby
|
763
853
|
Rails.application.routes.draw do
|
764
|
-
jsonapi_resources :
|
765
|
-
|
766
|
-
jsonapi_links :tags, only: [:show, :create]
|
854
|
+
jsonapi_resources :phone_numbers do
|
855
|
+
jsonapi_related_resource :contact
|
767
856
|
end
|
768
857
|
end
|
769
858
|
```
|
770
859
|
|
771
|
-
|
860
|
+
gives the following routes:
|
861
|
+
|
862
|
+
```
|
863
|
+
Prefix Verb URI Pattern Controller#Action
|
864
|
+
phone_number_contact GET /phone-numbers/:phone_number_id/contact(.:format) contacts#get_related_resource {:association=>"contact", :source=>"phone_numbers"}
|
865
|
+
phone_numbers GET /phone-numbers(.:format) phone_numbers#index
|
866
|
+
POST /phone-numbers(.:format) phone_numbers#create
|
867
|
+
new_phone_number GET /phone-numbers/new(.:format) phone_numbers#new
|
868
|
+
edit_phone_number GET /phone-numbers/:id/edit(.:format) phone_numbers#edit
|
869
|
+
phone_number GET /phone-numbers/:id(.:format) phone_numbers#show
|
870
|
+
PATCH /phone-numbers/:id(.:format) phone_numbers#update
|
871
|
+
PUT /phone-numbers/:id(.:format) phone_numbers#update
|
872
|
+
DELETE /phone-numbers/:id(.:format) phone_numbers#destroy
|
873
|
+
|
874
|
+
```
|
772
875
|
|
773
876
|
#### Formatting
|
774
877
|
|
data/lib/jsonapi/association.rb
CHANGED
@@ -7,10 +7,11 @@ module JSONAPI
|
|
7
7
|
@options = options
|
8
8
|
@acts_as_set = options.fetch(:acts_as_set, false) == true
|
9
9
|
@foreign_key = options[:foreign_key ] ? options[:foreign_key ].to_sym : nil
|
10
|
+
@module_path = options[:module_path] || ''
|
10
11
|
end
|
11
12
|
|
12
13
|
def primary_key
|
13
|
-
@primary_key ||= Resource.resource_for(@name)._primary_key
|
14
|
+
@primary_key ||= Resource.resource_for(@module_path + @name)._primary_key
|
14
15
|
end
|
15
16
|
|
16
17
|
class HasOne < Association
|
data/lib/jsonapi/error_codes.rb
CHANGED
data/lib/jsonapi/exceptions.rb
CHANGED
@@ -58,6 +58,15 @@ module JSONAPI
|
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
61
|
+
class HasManySetReplacementForbidden < Error
|
62
|
+
def errors
|
63
|
+
[JSONAPI::Error.new(code: JSONAPI::FORBIDDEN,
|
64
|
+
status: :forbidden,
|
65
|
+
title: 'Complete replacement forbidden',
|
66
|
+
detail: 'Complete replacement forbidden for this association')]
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
61
70
|
class FilterNotAllowed < Error
|
62
71
|
attr_accessor :filter
|
63
72
|
def initialize(filter)
|
data/lib/jsonapi/request.rb
CHANGED
@@ -171,9 +171,9 @@ module JSONAPI
|
|
171
171
|
def parse_sort_criteria(sort_criteria)
|
172
172
|
return unless sort_criteria
|
173
173
|
|
174
|
-
@sort_criteria = CSV.parse_line(sort_criteria).collect do |sort|
|
174
|
+
@sort_criteria = CSV.parse_line(URI.unescape(sort_criteria)).collect do |sort|
|
175
175
|
sort_criteria = {field: unformat_key(sort[1..-1]).to_s}
|
176
|
-
if sort.start_with?('+')
|
176
|
+
if sort.start_with?('+', ' ')
|
177
177
|
sort_criteria[:direction] = :asc
|
178
178
|
elsif sort.start_with?('-')
|
179
179
|
sort_criteria[:direction] = :desc
|
@@ -387,6 +387,10 @@ module JSONAPI
|
|
387
387
|
association_type,
|
388
388
|
verified_param_set[:has_one].values[0])
|
389
389
|
else
|
390
|
+
unless association.acts_as_set
|
391
|
+
raise JSONAPI::Exceptions::HasManySetReplacementForbidden.new
|
392
|
+
end
|
393
|
+
|
390
394
|
object_params = {links: {association.name => {linkage: data}}}
|
391
395
|
verified_param_set = parse_params(object_params, @resource_klass.updateable_fields(@context))
|
392
396
|
|
data/lib/jsonapi/resource.rb
CHANGED
@@ -127,7 +127,7 @@ module JSONAPI
|
|
127
127
|
association = self.class._associations[association_type]
|
128
128
|
|
129
129
|
association_key_values.each do |association_key_value|
|
130
|
-
related_resource = Resource.resource_for(association.type).find_by_key(association_key_value, context: @context)
|
130
|
+
related_resource = Resource.resource_for(self.class.module_path + association.type.to_s).find_by_key(association_key_value, context: @context)
|
131
131
|
|
132
132
|
# ToDo: Add option to skip relations that already exist instead of returning an error?
|
133
133
|
relation = @model.send(association.type).where(association.primary_key => association_key_value).first
|
@@ -203,11 +203,6 @@ module JSONAPI
|
|
203
203
|
base.attribute :id, format: :id
|
204
204
|
|
205
205
|
check_reserved_resource_name(base._type, base.name)
|
206
|
-
|
207
|
-
# If eager loading is on this is how all the resource types are setup
|
208
|
-
# If eager loading is off some resource types will be initialized in
|
209
|
-
# _resource_name_from_type
|
210
|
-
@@resource_types[base._type] ||= base.name.demodulize
|
211
206
|
end
|
212
207
|
|
213
208
|
def resource_for(type)
|
@@ -428,9 +423,7 @@ module JSONAPI
|
|
428
423
|
associations = []
|
429
424
|
|
430
425
|
@_associations.each do |key, association|
|
431
|
-
|
432
|
-
associations.push(key)
|
433
|
-
end
|
426
|
+
associations.push(key)
|
434
427
|
end
|
435
428
|
associations
|
436
429
|
end
|
@@ -520,6 +513,7 @@ module JSONAPI
|
|
520
513
|
|
521
514
|
def _associate(klass, *attrs)
|
522
515
|
options = attrs.extract_options!
|
516
|
+
options[:module_path] = module_path
|
523
517
|
|
524
518
|
attrs.each do |attr|
|
525
519
|
check_reserved_association_name(attr)
|
@@ -194,42 +194,34 @@ module JSONAPI
|
|
194
194
|
end
|
195
195
|
|
196
196
|
def process_request_operations
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
197
|
+
results = create_operations_processor.process(@request)
|
198
|
+
errors = results.select(&:has_errors?).flat_map(&:errors).compact
|
199
|
+
resources = results.reject(&:has_errors?).flat_map(&:resource).compact
|
200
|
+
|
201
|
+
status, json = case
|
202
|
+
when errors.any?
|
203
|
+
[errors[0].status, {errors: errors}]
|
204
|
+
when results.any? && resources.any?
|
205
|
+
res = resources.length > 1 ? resources : resources[0]
|
206
|
+
[results[0].code, processing_serializer.serialize_to_hash(res)]
|
207
207
|
else
|
208
|
-
|
209
|
-
end
|
208
|
+
[results[0].code, nil]
|
210
209
|
end
|
211
210
|
|
212
|
-
|
213
|
-
render status: errors[0].status, json: {errors: errors}
|
214
|
-
else
|
215
|
-
if results.length > 0 && resources.length > 0
|
216
|
-
serializer = JSONAPI::ResourceSerializer.new(resource_klass,
|
217
|
-
include: @request.include,
|
218
|
-
fields: @request.fields,
|
219
|
-
base_url: base_url,
|
220
|
-
key_formatter: key_formatter,
|
221
|
-
route_formatter: route_formatter)
|
222
|
-
|
223
|
-
render status: results[0].code,
|
224
|
-
json: serializer.serialize_to_hash(resources.length > 1 ? resources : resources[0])
|
225
|
-
else
|
226
|
-
render status: results[0].code, json: nil
|
227
|
-
end
|
228
|
-
end
|
211
|
+
render status: status, json: json
|
229
212
|
rescue => e
|
230
213
|
handle_exceptions(e)
|
231
214
|
end
|
232
215
|
|
216
|
+
def processing_serializer
|
217
|
+
JSONAPI::ResourceSerializer.new(resource_klass,
|
218
|
+
include: @request.include,
|
219
|
+
fields: @request.fields,
|
220
|
+
base_url: base_url,
|
221
|
+
key_formatter: key_formatter,
|
222
|
+
route_formatter: route_formatter)
|
223
|
+
end
|
224
|
+
|
233
225
|
# override this to process other exceptions
|
234
226
|
# Note: Be sure to either call super(e) or handle JSONAPI::Exceptions::Error and raise unhandled exceptions
|
235
227
|
def handle_exceptions(e)
|
data/lib/jsonapi/routing_ext.rb
CHANGED
@@ -130,7 +130,7 @@ module ActionDispatch
|
|
130
130
|
action: 'create_association', association: link_type.to_s, via: [:post]
|
131
131
|
end
|
132
132
|
|
133
|
-
if methods.include?(:update)
|
133
|
+
if methods.include?(:update)
|
134
134
|
match "links/#{formatted_association_name}", controller: res._type.to_s,
|
135
135
|
action: 'update_association', association: link_type.to_s, via: [:put, :patch]
|
136
136
|
end
|
@@ -174,6 +174,22 @@ class PostsControllerTest < ActionController::TestCase
|
|
174
174
|
assert_equal "A First Post", json_response['data'][0]['title']
|
175
175
|
end
|
176
176
|
|
177
|
+
# Plus symbol may be replaced by a space
|
178
|
+
def test_sorting_asc_with_space
|
179
|
+
get :index, {sort: ' title'}
|
180
|
+
|
181
|
+
assert_response :success
|
182
|
+
assert_equal "A First Post", json_response['data'][0]['title']
|
183
|
+
end
|
184
|
+
|
185
|
+
# Plus symbol may be sent uriencoded ('%2b')
|
186
|
+
def test_sorting_asc_with_encoded_plus
|
187
|
+
get :index, {sort: '%2btitle'}
|
188
|
+
|
189
|
+
assert_response :success
|
190
|
+
assert_equal "A First Post", json_response['data'][0]['title']
|
191
|
+
end
|
192
|
+
|
177
193
|
def test_sorting_desc
|
178
194
|
get :index, {sort: '-title'}
|
179
195
|
|
@@ -618,7 +634,7 @@ class PostsControllerTest < ActionController::TestCase
|
|
618
634
|
assert_response :success
|
619
635
|
assert json_response['data'].is_a?(Hash)
|
620
636
|
assert_equal '3', json_response['data']['links']['author']['linkage']['id']
|
621
|
-
assert_equal nil, json_response['data']['links']['section']['linkage']
|
637
|
+
assert_equal nil, json_response['data']['links']['section']['linkage']
|
622
638
|
assert_equal 'A great new Post', json_response['data']['title']
|
623
639
|
assert_equal 'AAAA', json_response['data']['body']
|
624
640
|
assert matches_array?([],
|
data/test/fixtures/comments.yml
CHANGED
@@ -158,7 +158,7 @@ class RequestTest < ActionDispatch::IntegrationTest
|
|
158
158
|
|
159
159
|
def test_update_association_without_content_type
|
160
160
|
ruby = Section.find_by(name: 'ruby')
|
161
|
-
patch '/posts/3/links/section', { '
|
161
|
+
patch '/posts/3/links/section', { 'data' => {type: 'sections', id: ruby.id.to_s }}.to_json
|
162
162
|
|
163
163
|
assert_equal 415, status
|
164
164
|
end
|
@@ -177,6 +177,31 @@ class RequestTest < ActionDispatch::IntegrationTest
|
|
177
177
|
assert_equal 204, status
|
178
178
|
end
|
179
179
|
|
180
|
+
def test_patch_update_association_has_many_acts_as_set
|
181
|
+
# Comments are acts_as_set=false so PUT/PATCH should respond with 403
|
182
|
+
|
183
|
+
rogue = Comment.find_by(body: 'Rogue Comment Here')
|
184
|
+
patch '/posts/5/links/comments', { 'data' => [{type: 'comments', id: rogue.id.to_s }]}.to_json, "CONTENT_TYPE" => JSONAPI::MEDIA_TYPE
|
185
|
+
|
186
|
+
assert_equal 403, status
|
187
|
+
end
|
188
|
+
|
189
|
+
def test_post_update_association_has_many
|
190
|
+
rogue = Comment.find_by(body: 'Rogue Comment Here')
|
191
|
+
post '/posts/5/links/comments', { 'data' => [{type: 'comments', id: rogue.id.to_s }]}.to_json, "CONTENT_TYPE" => JSONAPI::MEDIA_TYPE
|
192
|
+
|
193
|
+
assert_equal 204, status
|
194
|
+
end
|
195
|
+
|
196
|
+
def test_put_update_association_has_many_acts_as_set
|
197
|
+
# Comments are acts_as_set=false so PUT/PATCH should respond with 403. Note: JR currently treats PUT and PATCH as equivalent
|
198
|
+
|
199
|
+
rogue = Comment.find_by(body: 'Rogue Comment Here')
|
200
|
+
put '/posts/5/links/comments', { 'data' => [{type: 'comments', id: rogue.id.to_s }]}.to_json, "CONTENT_TYPE" => JSONAPI::MEDIA_TYPE
|
201
|
+
|
202
|
+
assert_equal 403, status
|
203
|
+
end
|
204
|
+
|
180
205
|
def test_index_content_type
|
181
206
|
get '/posts'
|
182
207
|
assert_match JSONAPI::MEDIA_TYPE, headers['Content-Type']
|
data/test/test_helper.rb
CHANGED
@@ -31,7 +31,7 @@ class SerializerTest < ActionDispatch::IntegrationTest
|
|
31
31
|
section: {
|
32
32
|
self: 'http://example.com/posts/1/links/section',
|
33
33
|
related: 'http://example.com/posts/1/section',
|
34
|
-
linkage:
|
34
|
+
linkage: nil
|
35
35
|
},
|
36
36
|
author: {
|
37
37
|
self: 'http://example.com/posts/1/links/author',
|
@@ -71,8 +71,7 @@ class SerializerTest < ActionDispatch::IntegrationTest
|
|
71
71
|
section: {
|
72
72
|
self: 'http://example.com/api/v1/posts/1/links/section',
|
73
73
|
related: 'http://example.com/api/v1/posts/1/section',
|
74
|
-
linkage:
|
75
|
-
}
|
74
|
+
linkage: nil
|
76
75
|
},
|
77
76
|
writer: {
|
78
77
|
self: 'http://example.com/api/v1/posts/1/links/writer',
|
@@ -136,8 +135,7 @@ class SerializerTest < ActionDispatch::IntegrationTest
|
|
136
135
|
section: {
|
137
136
|
self: '/posts/1/links/section',
|
138
137
|
related: '/posts/1/section',
|
139
|
-
linkage:
|
140
|
-
}
|
138
|
+
linkage: nil
|
141
139
|
},
|
142
140
|
author: {
|
143
141
|
self: '/posts/1/links/author',
|
@@ -205,8 +203,7 @@ class SerializerTest < ActionDispatch::IntegrationTest
|
|
205
203
|
section: {
|
206
204
|
self: '/posts/1/links/section',
|
207
205
|
related: '/posts/1/section',
|
208
|
-
linkage:
|
209
|
-
}
|
206
|
+
linkage: nil
|
210
207
|
},
|
211
208
|
author: {
|
212
209
|
self: '/posts/1/links/author',
|
@@ -276,8 +273,7 @@ class SerializerTest < ActionDispatch::IntegrationTest
|
|
276
273
|
section: {
|
277
274
|
self: '/posts/1/links/section',
|
278
275
|
related: '/posts/1/section',
|
279
|
-
linkage:
|
280
|
-
}
|
276
|
+
linkage: nil
|
281
277
|
},
|
282
278
|
author: {
|
283
279
|
self: '/posts/1/links/author',
|
@@ -424,8 +420,7 @@ class SerializerTest < ActionDispatch::IntegrationTest
|
|
424
420
|
section: {
|
425
421
|
self: '/posts/1/links/section',
|
426
422
|
related: '/posts/1/section',
|
427
|
-
linkage:
|
428
|
-
}
|
423
|
+
linkage: nil
|
429
424
|
},
|
430
425
|
author: {
|
431
426
|
self: '/posts/1/links/author',
|
@@ -503,8 +498,7 @@ class SerializerTest < ActionDispatch::IntegrationTest
|
|
503
498
|
section: {
|
504
499
|
self: '/posts/1/links/section',
|
505
500
|
related: '/posts/1/section',
|
506
|
-
linkage:
|
507
|
-
}
|
501
|
+
linkage: nil
|
508
502
|
},
|
509
503
|
author: {
|
510
504
|
self: '/posts/1/links/author',
|
@@ -587,8 +581,7 @@ class SerializerTest < ActionDispatch::IntegrationTest
|
|
587
581
|
preferences: {
|
588
582
|
self: "/people/2/links/preferences",
|
589
583
|
related: "/people/2/preferences",
|
590
|
-
linkage:
|
591
|
-
}
|
584
|
+
linkage: nil
|
592
585
|
}
|
593
586
|
}
|
594
587
|
},
|
@@ -676,8 +669,7 @@ class SerializerTest < ActionDispatch::IntegrationTest
|
|
676
669
|
section: {
|
677
670
|
self: '/posts/1/links/section',
|
678
671
|
related: '/posts/1/section',
|
679
|
-
linkage:
|
680
|
-
}
|
672
|
+
linkage: nil
|
681
673
|
},
|
682
674
|
author: {
|
683
675
|
self: '/posts/1/links/author',
|
@@ -1129,8 +1121,7 @@ class SerializerTest < ActionDispatch::IntegrationTest
|
|
1129
1121
|
planetType: {
|
1130
1122
|
self: '/planets/8/links/planet_type',
|
1131
1123
|
related: '/planets/8/planet_type',
|
1132
|
-
linkage:
|
1133
|
-
}
|
1124
|
+
linkage: nil
|
1134
1125
|
},
|
1135
1126
|
tags: {
|
1136
1127
|
self: '/planets/8/links/tags',
|
@@ -1192,8 +1183,7 @@ class SerializerTest < ActionDispatch::IntegrationTest
|
|
1192
1183
|
planetType: {
|
1193
1184
|
self: '/planets/8/links/planet_type',
|
1194
1185
|
related: '/planets/8/planet_type',
|
1195
|
-
linkage:
|
1196
|
-
}
|
1186
|
+
linkage: nil
|
1197
1187
|
},
|
1198
1188
|
tags: {
|
1199
1189
|
self: '/planets/8/links/tags',
|
@@ -1235,8 +1225,7 @@ class SerializerTest < ActionDispatch::IntegrationTest
|
|
1235
1225
|
author: {
|
1236
1226
|
self: '/preferences/1/links/author',
|
1237
1227
|
related: '/preferences/1/author',
|
1238
|
-
linkage:
|
1239
|
-
}
|
1228
|
+
linkage: nil
|
1240
1229
|
},
|
1241
1230
|
friends: {
|
1242
1231
|
self: '/preferences/1/links/friends',
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jsonapi-resources
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.0
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dan Gebhardt
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2015-04-
|
12
|
+
date: 2015-04-07 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -187,9 +187,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
187
187
|
version: '2.0'
|
188
188
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
189
189
|
requirements:
|
190
|
-
- - "
|
190
|
+
- - ">="
|
191
191
|
- !ruby/object:Gem::Version
|
192
|
-
version:
|
192
|
+
version: '0'
|
193
193
|
requirements: []
|
194
194
|
rubyforge_project:
|
195
195
|
rubygems_version: 2.4.5
|