jsonapi-resources 0.5.4 → 0.5.5

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: ef3f720982dbbec9843218ac90131071c97bfb9c
4
- data.tar.gz: 52fd35cd6696dfebf7b9fc69c8d22f09cffce8df
3
+ metadata.gz: dcb37444c599cb514483e80217f64409d7745411
4
+ data.tar.gz: eaeff3c3ee4183273ccb9cc59a1933781426c21f
5
5
  SHA512:
6
- metadata.gz: 6fec7c3f9bf100b0d4fd92fa4401285907529344e24eaa8d66fc82f5026911006102b1d72e4b39c688b83d4604ebbe66049f17c11487579f176c78b3165ec78c
7
- data.tar.gz: 607f360e9517e3f80341426d1126875a798b969e7740f371804be072e7b47142c3d26181d1534f25b011fb260b8135b67e29f2622650b947b90733c32bc14fb1
6
+ metadata.gz: 829b54dedc77b56e63757c0ea593a98b562d573fc2f1ba221baa036f429e365b21c28f99c846c681d681677f7bca9c240ca617d133f39a1ea1c9292ecaf5b1d4
7
+ data.tar.gz: dc68f574e96aa495ee6f6da7402869262864d169bdaa476b06948888935701f7601b2cdc9b0092c6a67bd9a89c1df96ae4c55c07a70a3f4223628d36a494588b
data/README.md CHANGED
@@ -54,6 +54,11 @@ class ContactResource < JSONAPI::Resource
54
54
  end
55
55
  ```
56
56
 
57
+ A jsonapi-resource generator is avaliable
58
+ ```
59
+ rails generate jsonapi:resource contact
60
+ ```
61
+
57
62
  ##### Abstract Resources
58
63
 
59
64
  Resources that are not backed by a model (purely used as base classes for other resources) should be declared as
@@ -1272,7 +1277,10 @@ JSONAPI.configure do |config|
1272
1277
  #:basic, :active_record, or custom
1273
1278
  config.operations_processor = :active_record
1274
1279
 
1275
- config.allowed_request_params = [:include, :fields, :format, :controller, :action, :sort, :page]
1280
+ # optional request features
1281
+ config.allow_include = true
1282
+ config.allow_sort = true
1283
+ config.allow_filter = true
1276
1284
 
1277
1285
  # :none, :offset, :paged, or a custom paginator name
1278
1286
  config.default_paginator = :none
@@ -0,0 +1,8 @@
1
+ Description:
2
+ Generator for JSONAPI Resources
3
+
4
+ Example:
5
+ rails generate jsonapi:resource Post
6
+
7
+ This will create:
8
+ app/resources/post_resource.rb
@@ -0,0 +1,14 @@
1
+ module Jsonapi
2
+ class ResourceGenerator < Rails::Generators::NamedBase
3
+ source_root File.expand_path('../templates', __FILE__)
4
+
5
+ def create_resource
6
+ template_file = File.join(
7
+ 'app/resources',
8
+ class_path,
9
+ "#{file_name}_resource.rb"
10
+ )
11
+ template 'jsonapi_resource.rb', template_file
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,4 @@
1
+ <% module_namespacing do -%>
2
+ class <%= class_name %>Resource < JSONAPI::Resource
3
+ end
4
+ <% end -%>
@@ -9,7 +9,9 @@ module JSONAPI
9
9
  :route_format,
10
10
  :route_formatter,
11
11
  :operations_processor,
12
- :allowed_request_params,
12
+ :allow_include,
13
+ :allow_sort,
14
+ :allow_filter,
13
15
  :default_paginator,
14
16
  :default_page_size,
15
17
  :maximum_page_size,
@@ -31,7 +33,10 @@ module JSONAPI
31
33
  #:basic, :active_record, or custom
32
34
  self.operations_processor = :active_record
33
35
 
34
- self.allowed_request_params = [:include, :fields, :format, :controller, :action, :sort, :page]
36
+ # optional request features
37
+ self.allow_include = true
38
+ self.allow_sort = true
39
+ self.allow_filter = true
35
40
 
36
41
  # :none, :offset, :paged, or a custom paginator name
37
42
  self.default_paginator = :none
@@ -79,7 +84,7 @@ module JSONAPI
79
84
  @operations_processor = JSONAPI::OperationsProcessor.operations_processor_for(@operations_processor_name)
80
85
  end
81
86
 
82
- attr_writer :allowed_request_params
87
+ attr_writer :allow_include, :allow_sort, :allow_filter
83
88
 
84
89
  attr_writer :default_paginator
85
90
 
@@ -317,8 +317,8 @@ module JSONAPI
317
317
  def json_api_error(attr_key, message)
318
318
  JSONAPI::Error.new(code: JSONAPI::VALIDATION_ERROR,
319
319
  status: :unprocessable_entity,
320
- title: "#{format_key(attr_key)} - #{message}",
321
- detail: message,
320
+ title: message,
321
+ detail: "#{format_key(attr_key)} - #{message}",
322
322
  source: { pointer: pointer(attr_key) })
323
323
  end
324
324
 
@@ -31,8 +31,10 @@ module JSONAPI
31
31
  "#{ primary_resources_url }?#{ query_params.to_query }"
32
32
  end
33
33
 
34
- def relationships_related_link(source, relationship)
35
- "#{ self_link(source) }/#{ route_for_relationship(relationship) }"
34
+ def relationships_related_link(source, relationship, query_params = {})
35
+ url = "#{ self_link(source) }/#{ route_for_relationship(relationship) }"
36
+ url = "#{ url }?#{ query_params.to_query }" if query_params.present?
37
+ url
36
38
  end
37
39
 
38
40
  def relationships_self_link(source, relationship)
@@ -149,15 +149,43 @@ module JSONAPI
149
149
  @transactional = false
150
150
  end
151
151
 
152
- def apply
153
- source_resource = @source_klass.find_by_key(@source_id, context: @context)
152
+ def record_count
153
+ @_record_count ||= records.count
154
+ end
155
+
156
+ def source_resource
157
+ @_source_resource ||= @source_klass.find_by_key(@source_id, context: @context)
158
+ end
159
+
160
+ def records
161
+ related_resource_records = source_resource.records_for(@relationship_type)
162
+ @resource_klass.filter_records(@filters, @options, related_resource_records)
163
+ end
164
+
165
+ def pagination_params
166
+ if @paginator && JSONAPI.configuration.top_level_links_include_pagination
167
+ options = {}
168
+ options[:record_count] = record_count if @paginator.class.requires_record_count
169
+ @paginator.links_page_params(options)
170
+ else
171
+ {}
172
+ end
173
+ end
174
+
175
+ def options
176
+ opts = {}
177
+ opts.merge!(pagination_params: pagination_params) if JSONAPI.configuration.top_level_links_include_pagination
178
+ opts.merge!(record_count: pagination_params) if JSONAPI.configuration.top_level_meta_include_record_count
179
+ opts
180
+ end
154
181
 
182
+ def apply
155
183
  related_resource = source_resource.public_send(@relationship_type,
156
184
  filters: @filters,
157
185
  sort_criteria: @sort_criteria,
158
186
  paginator: @paginator)
159
187
 
160
- return JSONAPI::ResourceOperationResult.new(:ok, related_resource)
188
+ return JSONAPI::RelatedResourcesOperationResult.new(:ok, source_resource, @relationship_type, related_resource, options)
161
189
 
162
190
  rescue JSONAPI::Exceptions::Error => e
163
191
  return JSONAPI::ErrorsOperationResult.new(e.errors[0].code, e.errors)
@@ -42,6 +42,16 @@ module JSONAPI
42
42
  end
43
43
  end
44
44
 
45
+ class RelatedResourcesOperationResult < ResourcesOperationResult
46
+ attr_accessor :source_resource, :_type
47
+
48
+ def initialize(code, source_resource, type, resources, options = {})
49
+ @source_resource = source_resource
50
+ @_type = type
51
+ super(code, resources, options)
52
+ end
53
+ end
54
+
45
55
  class LinksObjectOperationResult < OperationResult
46
56
  attr_accessor :parent_resource, :relationship
47
57
 
@@ -74,8 +74,12 @@ class OffsetPaginator < JSONAPI::Paginator
74
74
  end
75
75
 
76
76
  if record_count
77
+ last_offset = record_count - @limit
78
+
79
+ last_offset = 0 if last_offset < 0
80
+
77
81
  links_page_params['last'] = {
78
- 'offset' => record_count - @limit,
82
+ 'offset' => last_offset,
79
83
  'limit' => @limit
80
84
  }
81
85
  end
@@ -159,7 +163,7 @@ class PagedPaginator < JSONAPI::Paginator
159
163
 
160
164
  if record_count
161
165
  links_page_params['last'] = {
162
- 'number' => page_count,
166
+ 'number' => page_count == 0 ? 1 : page_count,
163
167
  'size' => @size
164
168
  }
165
169
  end
@@ -196,6 +196,10 @@ module JSONAPI
196
196
  def parse_include_directives(include)
197
197
  return if include.nil?
198
198
 
199
+ unless JSONAPI.configuration.allow_include
200
+ fail JSONAPI::Exceptions::ParametersNotAllowed.new([:include])
201
+ end
202
+
199
203
  included_resources = CSV.parse_line(include)
200
204
  return if included_resources.nil?
201
205
 
@@ -211,6 +215,10 @@ module JSONAPI
211
215
  def parse_filters(filters)
212
216
  return unless filters
213
217
 
218
+ unless JSONAPI.configuration.allow_filter
219
+ fail JSONAPI::Exceptions::ParametersNotAllowed.new([:filter])
220
+ end
221
+
214
222
  unless filters.class.method_defined?(:each)
215
223
  @errors.concat(JSONAPI::Exceptions::InvalidFiltersSyntax.new(filters).errors)
216
224
  return
@@ -236,6 +244,10 @@ module JSONAPI
236
244
  def parse_sort_criteria(sort_criteria)
237
245
  return unless sort_criteria.present?
238
246
 
247
+ unless JSONAPI.configuration.allow_sort
248
+ fail JSONAPI::Exceptions::ParametersNotAllowed.new([:sort])
249
+ end
250
+
239
251
  @sort_criteria = CSV.parse_line(URI.unescape(sort_criteria)).collect do |sort|
240
252
  if sort.start_with?('-')
241
253
  sort_criteria = { field: unformat_key(sort[1..-1]).to_s }
@@ -472,8 +472,7 @@ module JSONAPI
472
472
  records
473
473
  end
474
474
 
475
- def filter_records(filters, options)
476
- records = records(options)
475
+ def filter_records(filters, options, records = records(options))
477
476
  records = apply_filters(records, filters, options)
478
477
  apply_includes(records, options)
479
478
  end
@@ -483,7 +482,7 @@ module JSONAPI
483
482
  end
484
483
 
485
484
  def find_count(filters, options = {})
486
- filter_records(filters, options).count
485
+ filter_records(filters, options).count(:all)
487
486
  end
488
487
 
489
488
  # Override this method if you have more complex requirements than this basic find method provides
@@ -686,7 +685,7 @@ module JSONAPI
686
685
  check_reserved_relationship_name(attr)
687
686
 
688
687
  # Initialize from an ActiveRecord model's properties
689
- if _model_class && _model_class < ActiveRecord::Base
688
+ if _model_class && _model_class.ancestors.collect{|ancestor| ancestor.name}.include?('ActiveRecord::Base')
690
689
  model_association = _model_class.reflect_on_association(attr)
691
690
  if model_association
692
691
  options[:class_name] ||= model_association.class_name
@@ -1,5 +1,5 @@
1
1
  module JSONAPI
2
2
  module Resources
3
- VERSION = '0.5.4'
3
+ VERSION = '0.5.5'
4
4
  end
5
5
  end
@@ -69,25 +69,33 @@ module JSONAPI
69
69
  links.merge!(result.links)
70
70
 
71
71
  # Build pagination links
72
- if result.is_a?(JSONAPI::ResourcesOperationResult)
73
- result.pagination_params.each_pair do |link_name, params|
74
- query_params = {}
75
- query_params[:page] = params
76
-
77
- request = @options[:request]
78
- query_params[:fields] = request.params[:fields] if request.params[:fields]
79
- query_params[:include] = request.params[:include] if request.params[:include]
80
- query_params[:sort] = request.params[:sort] if request.params[:sort]
81
- query_params[:filter] = request.params[:filter] if request.params[:filter]
82
-
83
- links[link_name] = serializer.find_link(query_params)
84
- end
72
+ if result.is_a?(JSONAPI::ResourcesOperationResult) || result.is_a?(JSONAPI::RelatedResourcesOperationResult)
73
+ result.pagination_params.each_pair do |link_name, params|
74
+ if result.is_a?(JSONAPI::RelatedResourcesOperationResult)
75
+ relationship = result.source_resource.class._relationships[result._type.to_sym]
76
+ links[link_name] = serializer.url_generator.relationships_related_link(result.source_resource, relationship, query_params(params))
77
+ else
78
+ links[link_name] = serializer.find_link(query_params(params))
79
+ end
80
+ end
85
81
  end
86
82
  end
87
83
 
88
84
  links.deep_transform_keys { |key| @key_formatter.format(key) }
89
85
  end
90
86
 
87
+ def query_params(params)
88
+ query_params = {}
89
+ query_params[:page] = params
90
+
91
+ request = @options[:request]
92
+ query_params[:fields] = request.params[:fields] if request.params[:fields]
93
+ query_params[:include] = request.params[:include] if request.params[:include]
94
+ query_params[:sort] = request.params[:sort] if request.params[:sort]
95
+ query_params[:filter] = request.params[:filter] if request.params[:filter]
96
+ query_params
97
+ end
98
+
91
99
  def results_to_hash
92
100
  if @operation_results.has_errors?
93
101
  { errors: @operation_results.all_errors }
@@ -69,6 +69,14 @@ class PostsControllerTest < ActionController::TestCase
69
69
  assert_equal 1, json_response['included'].size
70
70
  end
71
71
 
72
+ def test_index_filter_not_allowed
73
+ JSONAPI.configuration.allow_filter = false
74
+ get :index, {filter: {id: '1'}}
75
+ assert_response :bad_request
76
+ ensure
77
+ JSONAPI.configuration.allow_filter = true
78
+ end
79
+
72
80
  def test_index_include_one_level_query_count
73
81
  count_queries do
74
82
  get :index, {include: 'author'}
@@ -239,6 +247,14 @@ class PostsControllerTest < ActionController::TestCase
239
247
  assert_match /asdfg is not a valid sort criteria for post/, response.body
240
248
  end
241
249
 
250
+ def test_show_single_with_sort_disallowed
251
+ JSONAPI.configuration.allow_sort = false
252
+ get :index, {sort: 'title,body'}
253
+ assert_response :bad_request
254
+ ensure
255
+ JSONAPI.configuration.allow_sort = true
256
+ end
257
+
242
258
  def test_excluded_sort_param
243
259
  get :index, {sort: 'id'}
244
260
 
@@ -276,6 +292,14 @@ class PostsControllerTest < ActionController::TestCase
276
292
  assert_equal 2, json_response['included'].size
277
293
  end
278
294
 
295
+ def test_show_single_with_include_disallowed
296
+ JSONAPI.configuration.allow_include = false
297
+ get :show, {id: '1', include: 'comments'}
298
+ assert_response :bad_request
299
+ ensure
300
+ JSONAPI.configuration.allow_include = true
301
+ end
302
+
279
303
  def test_show_single_with_fields
280
304
  get :show, {id: '1', fields: {posts: 'author'}}
281
305
  assert_response :success
@@ -396,12 +420,12 @@ class PostsControllerTest < ActionController::TestCase
396
420
  assert_response :unprocessable_entity
397
421
 
398
422
  assert_equal "/data/relationships/author", json_response['errors'][0]['source']['pointer']
399
- assert_equal "can't be blank", json_response['errors'][0]['detail']
400
- assert_equal "author - can't be blank", json_response['errors'][0]['title']
423
+ assert_equal "can't be blank", json_response['errors'][0]['title']
424
+ assert_equal "author - can't be blank", json_response['errors'][0]['detail']
401
425
 
402
426
  assert_equal "/data/attributes/title", json_response['errors'][1]['source']['pointer']
403
- assert_equal "is too long (maximum is 35 characters)", json_response['errors'][1]['detail']
404
- assert_equal "title - is too long (maximum is 35 characters)", json_response['errors'][1]['title']
427
+ assert_equal "is too long (maximum is 35 characters)", json_response['errors'][1]['title']
428
+ assert_equal "title - is too long (maximum is 35 characters)", json_response['errors'][1]['detail']
405
429
  end
406
430
 
407
431
  def test_create_multiple
@@ -2212,12 +2236,12 @@ class FactsControllerTest < ActionController::TestCase
2212
2236
  assert_response :unprocessable_entity
2213
2237
 
2214
2238
  assert_equal "/data/attributes/spouse-name", json_response['errors'][0]['source']['pointer']
2215
- assert_equal "can't be blank", json_response['errors'][0]['detail']
2216
- assert_equal "spouse-name - can't be blank", json_response['errors'][0]['title']
2239
+ assert_equal "can't be blank", json_response['errors'][0]['title']
2240
+ assert_equal "spouse-name - can't be blank", json_response['errors'][0]['detail']
2217
2241
 
2218
2242
  assert_equal "/data/attributes/bio", json_response['errors'][1]['source']['pointer']
2219
- assert_equal "can't be blank", json_response['errors'][1]['detail']
2220
- assert_equal "bio - can't be blank", json_response['errors'][1]['title']
2243
+ assert_equal "can't be blank", json_response['errors'][1]['title']
2244
+ assert_equal "bio - can't be blank", json_response['errors'][1]['detail']
2221
2245
  end
2222
2246
  end
2223
2247
 
@@ -389,6 +389,25 @@ class RequestTest < ActionDispatch::IntegrationTest
389
389
  assert_equal 'This is comment 18 on book 1.', json_response['data'][9]['attributes']['body']
390
390
  end
391
391
 
392
+ def test_pagination_related_resources_links
393
+ Api::V2::BookResource.paginator :offset
394
+ Api::V2::BookCommentResource.paginator :offset
395
+ get '/api/v2/books/1/book_comments?page[limit]=10'
396
+ assert_equal 'http://www.example.com/api/v2/books/1/book_comments?page%5Blimit%5D=10&page%5Boffset%5D=0', json_response['links']['first']
397
+ assert_equal 'http://www.example.com/api/v2/books/1/book_comments?page%5Blimit%5D=10&page%5Boffset%5D=10', json_response['links']['next']
398
+ assert_equal 'http://www.example.com/api/v2/books/1/book_comments?page%5Blimit%5D=10&page%5Boffset%5D=41', json_response['links']['last']
399
+ end
400
+
401
+ def test_pagination_related_resources_without_related
402
+ Api::V2::BookResource.paginator :offset
403
+ Api::V2::BookCommentResource.paginator :offset
404
+ get '/api/v2/books/10/book_comments'
405
+ assert_equal 200, status
406
+ assert_nil json_response['links']['next']
407
+ assert_equal 'http://www.example.com/api/v2/books/10/book_comments?page%5Blimit%5D=10&page%5Boffset%5D=0', json_response['links']['first']
408
+ assert_equal 'http://www.example.com/api/v2/books/10/book_comments?page%5Blimit%5D=10&page%5Boffset%5D=0', json_response['links']['last']
409
+ end
410
+
392
411
  def test_pagination_related_resources_data_includes
393
412
  Api::V2::BookResource.paginator :offset
394
413
  Api::V2::BookCommentResource.paginator :offset
@@ -398,6 +417,17 @@ class RequestTest < ActionDispatch::IntegrationTest
398
417
  assert_equal 'This is comment 18 on book 1.', json_response['data'][9]['attributes']['body']
399
418
  end
400
419
 
420
+ def test_pagination_empty_results
421
+ Api::V2::BookResource.paginator :offset
422
+ Api::V2::BookCommentResource.paginator :offset
423
+ get '/api/v2/books?filter[id]=2000&page[limit]=10'
424
+ assert_equal 200, status
425
+ assert_equal 0, json_response['data'].size
426
+ assert_nil json_response['links']['next']
427
+ assert_equal 'http://www.example.com/api/v2/books?filter%5Bid%5D=2000&page%5Blimit%5D=10&page%5Boffset%5D=0', json_response['links']['first']
428
+ assert_equal 'http://www.example.com/api/v2/books?filter%5Bid%5D=2000&page%5Blimit%5D=10&page%5Boffset%5D=0', json_response['links']['last']
429
+ end
430
+
401
431
  # def test_pagination_related_resources_data_includes
402
432
  # Api::V2::BookResource.paginator :none
403
433
  # Api::V2::BookCommentResource.paginator :none
@@ -691,4 +721,32 @@ class RequestTest < ActionDispatch::IntegrationTest
691
721
  assert_equal 204, status
692
722
  end
693
723
 
724
+ def test_include_parameter_allowed
725
+ get '/api/v2/books/1/book_comments?include=author'
726
+ assert_equal 200, status
727
+ end
728
+
729
+ def test_include_parameter_not_allowed
730
+ JSONAPI.configuration.allow_include = false
731
+ get '/api/v2/books/1/book_comments?include=author'
732
+ assert_equal 400, status
733
+ ensure
734
+ JSONAPI.configuration.allow_include = true
735
+ end
736
+
737
+ def test_filter_parameter_not_allowed
738
+ JSONAPI.configuration.allow_filter = false
739
+ get '/api/v2/books?filter[author]=1'
740
+ assert_equal 400, status
741
+ ensure
742
+ JSONAPI.configuration.allow_filter = true
743
+ end
744
+
745
+ def test_sort_parameter_not_allowed
746
+ JSONAPI.configuration.allow_sort = false
747
+ get '/api/v2/books?sort=title'
748
+ assert_equal 400, status
749
+ ensure
750
+ JSONAPI.configuration.allow_sort = true
751
+ end
694
752
  end
@@ -0,0 +1,25 @@
1
+ require 'test_helper'
2
+ require 'generators/jsonapi/resource_generator'
3
+
4
+ module Jsonapi
5
+ class ResourceGeneratorTest < Rails::Generators::TestCase
6
+ tests ResourceGenerator
7
+ destination Rails.root.join('../resources')
8
+ setup :prepare_destination
9
+ teardown :cleanup_destination_root
10
+
11
+ def cleanup_destination_root
12
+ FileUtils.rm_rf destination_root
13
+ end
14
+
15
+ test "resource is created" do
16
+ run_generator ["post"]
17
+ assert_file 'app/resources/post_resource.rb', /class PostResource < JSONAPI::Resource/
18
+ end
19
+
20
+ test "resource is created with namespace" do
21
+ run_generator ["api/v1/post"]
22
+ assert_file 'app/resources/api/v1/post_resource.rb', /class Api::V1::PostResource < JSONAPI::Resource/
23
+ end
24
+ end
25
+ end
@@ -82,6 +82,45 @@ class OffsetPaginatorTest < ActiveSupport::TestCase
82
82
  assert_equal 0, paginator.offset
83
83
  end
84
84
 
85
+ def test_offset_links_page_params_empty_results
86
+ params = ActionController::Parameters.new(
87
+ {
88
+ limit: 5,
89
+ offset: 0
90
+ }
91
+ )
92
+
93
+ paginator = OffsetPaginator.new(params)
94
+ links_params = paginator.links_page_params(record_count: 0)
95
+
96
+ assert_equal 2, links_params.size
97
+
98
+ assert_equal 5, links_params['first']['limit']
99
+ assert_equal 0, links_params['first']['offset']
100
+
101
+ assert_equal 5, links_params['last']['limit']
102
+ assert_equal 0, links_params['last']['offset']
103
+ end
104
+
105
+ def test_offset_links_page_params_small_resultsets
106
+ params = ActionController::Parameters.new(
107
+ {
108
+ limit: 5,
109
+ offset: 0
110
+ }
111
+ )
112
+
113
+ paginator = OffsetPaginator.new(params)
114
+ links_params = paginator.links_page_params(record_count: 3)
115
+
116
+ assert_equal 2, links_params.size
117
+
118
+ assert_equal 5, links_params['first']['limit']
119
+ assert_equal 0, links_params['first']['offset']
120
+
121
+ assert_equal 5, links_params['last']['limit']
122
+ assert_equal 0, links_params['last']['offset']
123
+ end
85
124
 
86
125
  def test_offset_links_page_params_large_data_set_start
87
126
  params = ActionController::Parameters.new(
@@ -82,6 +82,45 @@ class PagedPaginatorTest < ActiveSupport::TestCase
82
82
  assert_equal 1, paginator.number
83
83
  end
84
84
 
85
+ def test_paged_links_page_params_empty_results
86
+ params = ActionController::Parameters.new(
87
+ {
88
+ size: 5,
89
+ number: 1
90
+ }
91
+ )
92
+
93
+ paginator = PagedPaginator.new(params)
94
+ links_params = paginator.links_page_params(record_count: 0)
95
+
96
+ assert_equal 2, links_params.size
97
+
98
+ assert_equal 5, links_params['first']['size']
99
+ assert_equal 1, links_params['first']['number']
100
+
101
+ assert_equal 5, links_params['last']['size']
102
+ assert_equal 1, links_params['last']['number']
103
+ end
104
+
105
+ def test_paged_links_page_params_small_resultsets
106
+ params = ActionController::Parameters.new(
107
+ {
108
+ size: 5,
109
+ number: 1
110
+ }
111
+ )
112
+
113
+ paginator = PagedPaginator.new(params)
114
+ links_params = paginator.links_page_params(record_count: 3)
115
+
116
+ assert_equal 2, links_params.size
117
+
118
+ assert_equal 5, links_params['first']['size']
119
+ assert_equal 1, links_params['first']['number']
120
+
121
+ assert_equal 5, links_params['last']['size']
122
+ assert_equal 1, links_params['last']['number']
123
+ end
85
124
 
86
125
  def test_paged_links_page_params_large_data_set_start_full_pages
87
126
  params = ActionController::Parameters.new(
@@ -169,6 +169,23 @@ class LinkBuilderTest < ActionDispatch::IntegrationTest
169
169
  builder.relationships_related_link(source, relationship)
170
170
  end
171
171
 
172
+ def test_relationships_related_link_with_query_params
173
+ config = {
174
+ base_url: @base_url,
175
+ route_formatter: @route_formatter,
176
+ primary_resource_klass: Api::V1::PersonResource
177
+ }
178
+
179
+ builder = JSONAPI::LinkBuilder.new(config)
180
+ source = Api::V1::PersonResource.new(@steve)
181
+ relationship = JSONAPI::Relationship::ToMany.new("posts", {})
182
+ expected_link = "#{ @base_url }/api/v1/people/#{ @steve.id }/posts?page%5Blimit%5D=12&page%5Boffset%5D=0"
183
+ query = { page: { offset: 0, limit: 12 } }
184
+
185
+ assert_equal expected_link,
186
+ builder.relationships_related_link(source, relationship, query)
187
+ end
188
+
172
189
  def test_query_link_for_regular_app
173
190
  config = {
174
191
  base_url: @base_url,
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.5.4
4
+ version: 0.5.5
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-07-29 00:00:00.000000000 Z
12
+ date: 2015-08-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -139,6 +139,9 @@ files:
139
139
  - README.md
140
140
  - Rakefile
141
141
  - jsonapi-resources.gemspec
142
+ - lib/generators/jsonapi/USAGE
143
+ - lib/generators/jsonapi/resource_generator.rb
144
+ - lib/generators/jsonapi/templates/jsonapi_resource.rb
142
145
  - lib/jsonapi-resources.rb
143
146
  - lib/jsonapi/active_record_operations_processor.rb
144
147
  - lib/jsonapi/acts_as_resource_controller.rb
@@ -202,6 +205,7 @@ files:
202
205
  - test/helpers/value_matchers_test.rb
203
206
  - test/integration/requests/request_test.rb
204
207
  - test/integration/routes/routes_test.rb
208
+ - test/lib/generators/jsonapi/resource_generator_test.rb
205
209
  - test/test_helper.rb
206
210
  - test/unit/jsonapi_request/jsonapi_request_test.rb
207
211
  - test/unit/operation/operations_processor_test.rb
@@ -276,6 +280,7 @@ test_files:
276
280
  - test/helpers/value_matchers_test.rb
277
281
  - test/integration/requests/request_test.rb
278
282
  - test/integration/routes/routes_test.rb
283
+ - test/lib/generators/jsonapi/resource_generator_test.rb
279
284
  - test/test_helper.rb
280
285
  - test/unit/jsonapi_request/jsonapi_request_test.rb
281
286
  - test/unit/operation/operations_processor_test.rb
@@ -287,3 +292,4 @@ test_files:
287
292
  - test/unit/serializer/polymorphic_serializer_test.rb
288
293
  - test/unit/serializer/response_document_test.rb
289
294
  - test/unit/serializer/serializer_test.rb
295
+ has_rdoc: