jsonapi-resources 0.5.4 → 0.5.5

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: 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: