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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9adad069e77c8437a28d82ed522448f10282551d
4
- data.tar.gz: d5cbb50ba9bec003e03d50f54c930dd2b47f16ad
3
+ metadata.gz: 7f8dd7b98dfa7f20a9b75456fd8ca066ae807fd0
4
+ data.tar.gz: 4aaa07053a74089ef0880f4154e79261a97529d9
5
5
  SHA512:
6
- metadata.gz: a8453158ff6be52c6fa81fdbcda63543fb9d2952dd9ff3c10c411c543e718bbf52ca0eb1c8104a02e80d856c33a18498dbff5644ec0b6a5645266e3c79d0380a
7
- data.tar.gz: d42d5196aa3f1728356d5378f45f16fcd5180304dcdc9d380b2d937934f2bdc9a6cb14f4748dcb0c4b43c3a46efc14214dc96a573d224ac7ad17ed3ff6b57a2c
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 and controller actions. This will also setup mappings for relationship URLs for a resource's associations. For example:
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
- require 'jsonapi/routing_ext'
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 URI Pattern Controller#Action
727
- contact_links_phone_numbers GET /contacts/:contact_id/links/phone_numbers(.:format) contacts#show_association {:association=>"phone_numbers"}
728
- POST /contacts/:contact_id/links/phone_numbers(.:format) contacts#create_association {:association=>"phone_numbers"}
729
- DELETE /contacts/:contact_id/links/phone_numbers/:keys(.:format) contacts#destroy_association {:association=>"phone_numbers"}
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
- phone_number_links_contact GET /phone_numbers/:phone_number_id/links/contact(.:format) phone_numbers#show_association {:association=>"contact"}
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
- ##### `jsonapi_resource`
815
+ The new routes allow you to show, create and destroy the associations between resources.
752
816
 
753
- Like `jsonapi_resources`, but for resources you lookup without an id.
817
+ ###### `jsonapi_related_resources`
754
818
 
755
- ##### `jsonapi_links`
819
+ Creates a nested route to GET the related has_many resources. For example:
756
820
 
757
- You can control the relationship routes by passing a block into `jsonapi_resources` or `jsonapi_resource`. An empty block
758
- will not create any relationship routes.
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
- You can add relationship routes in with `jsonapi_links`, for example:
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 :posts, except: [:destroy] do
765
- jsonapi_link :author, except: [:destroy]
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
- This will create relationship routes for author (show and create, but not destroy) and for tags (again show and create, but not destroy).
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
 
@@ -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
@@ -19,6 +19,7 @@ module JSONAPI
19
19
  INVALID_PAGE_VALUE = 118
20
20
  INVALID_SORT_FORMAT = 119
21
21
  INVALID_FIELD_FORMAT = 120
22
+ FORBIDDEN = 403
22
23
  RECORD_NOT_FOUND = 404
23
24
  UNSUPPORTED_MEDIA_TYPE = 415
24
25
  LOCKED = 423
@@ -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)
@@ -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
 
@@ -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
- if association.is_a?(JSONAPI::Association::HasOne) || association.acts_as_set
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
- op = create_operations_processor
198
-
199
- results = op.process(@request)
200
-
201
- errors = []
202
- resources = []
203
-
204
- results.each do |result|
205
- if result.has_errors?
206
- errors.concat(result.errors)
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
- resources.push(result.resource) unless result.resource.nil?
209
- end
208
+ [results[0].code, nil]
210
209
  end
211
210
 
212
- if errors.count > 0
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)
@@ -250,6 +250,8 @@ module JSONAPI
250
250
  if linkage_id
251
251
  linkage[:type] = format_route(association.type)
252
252
  linkage[:id] = linkage_id
253
+ else
254
+ linkage = nil
253
255
  end
254
256
  linkage
255
257
  end
@@ -1,5 +1,5 @@
1
1
  module JSONAPI
2
2
  module Resources
3
- VERSION = "0.3.0.pre2"
3
+ VERSION = "0.3.0"
4
4
  end
5
5
  end
@@ -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) && res._association(link_type).acts_as_set
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']['id']
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?([],
@@ -14,4 +14,8 @@ post_2_thanks_man:
14
14
  id: 3
15
15
  post_id: 2
16
16
  body: Thanks man. Great post. But what is JR?
17
- author_id: 2
17
+ author_id: 2
18
+
19
+ rogue_comment:
20
+ body: Rogue Comment Here
21
+ author_id: 3
@@ -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', { 'sections' => {type: 'sections', id: ruby.id.to_s }}.to_json
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']
@@ -27,7 +27,6 @@ end
27
27
  puts "Testing With RAILS VERSION #{Rails.version}"
28
28
 
29
29
  class TestApp < Rails::Application
30
- config.eager_load = false
31
30
  config.root = File.dirname(__FILE__)
32
31
  config.session_store :cookie_store, key: 'session'
33
32
  config.secret_key_base = 'secret'
@@ -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.pre2
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-01 00:00:00.000000000 Z
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: 1.3.1
192
+ version: '0'
193
193
  requirements: []
194
194
  rubyforge_project:
195
195
  rubygems_version: 2.4.5