jsonapi-resources 0.3.0.pre2 → 0.3.0

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