Skip to content

Commit ad10ae9

Browse files
author
Yohan Robert
committed
Add config for disabling JsonApi automatic pagination
The following configuration can now be used to disable automatic pagination links when using JsonApi adapter: ActiveModelSerializer.config.collection_serializer = ActiveModel::Serializer::Nonpaginatedcollectionserializer
1 parent db87f8d commit ad10ae9

12 files changed

+276
-229
lines changed

docs/howto/add_pagination_links.md

Lines changed: 52 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -2,47 +2,34 @@
22

33
# How to add pagination links
44

5-
### JSON API adapter
5+
## JSON API adapter
66

7-
Pagination links will be included in your response automatically as long as
8-
the resource is paginated and if you are using the ```JsonApi``` adapter.
7+
When using the `JsonApi` adapter, pagination links will be automatically included if you use [Kaminari](https://github.com/amatsuda/kaminari)
8+
or [WillPaginate](https://github.com/mislav/will_paginate) within a Rails controller:
99

10-
If you want pagination links in your response, use [Kaminari](https://github.com/amatsuda/kaminari)
11-
or [WillPaginate](https://github.com/mislav/will_paginate).
12-
13-
Although the others adapters does not have this feature, it is possible to
14-
implement pagination links to `JSON` adapter. For more information about it,
15-
please see in our docs
16-
17-
###### Kaminari examples
10+
* Using Kaminari:
1811

1912
```ruby
20-
#array
21-
@posts = Kaminari.paginate_array([1, 2, 3]).page(3).per(1)
22-
render json: @posts
23-
24-
#active_record
25-
@posts = Post.page(3).per(1)
26-
render json: @posts
13+
class PostsController < ApplicationController
14+
def index
15+
posts = Post.page(params[:page]).per(params[:per_page])
16+
render json: posts
17+
end
18+
end
2719
```
2820

29-
###### WillPaginate examples
30-
31-
```ruby
32-
#array
33-
@posts = [1,2,3].paginate(page: 3, per_page: 1)
34-
render json: @posts
35-
36-
#active_record
37-
@posts = Post.page(3).per_page(1)
38-
render json: @posts
39-
```
21+
* Using WillPaginate:
4022

4123
```ruby
42-
ActiveModelSerializers.config.adapter = :json_api
24+
class PostsController < ApplicationController
25+
def index
26+
posts = Post.page(params[:page]).per_page(params[:per_page])
27+
render json: posts
28+
end
29+
end
4330
```
4431

45-
ex:
32+
The response might look like:
4633
```json
4734
{
4835
"data": [
@@ -67,34 +54,50 @@ ex:
6754
}
6855
```
6956

70-
ActiveModelSerializers pagination relies on a paginated collection with the methods `current_page`, `total_pages`, and `size`, such as are supported by both [Kaminari](https://github.com/amatsuda/kaminari) or [WillPaginate](https://github.com/mislav/will_paginate).
71-
57+
ActiveModelSerializers pagination relies on paginated collections which define the methods `#current_page`, `#total_pages`, and `#size`.
58+
Such methods are supported by both [Kaminari](https://github.com/amatsuda/kaminari) or [WillPaginate](https://github.com/mislav/will_paginate),
59+
but you can also roll out your own paginated collection by defining these methods.
7260

73-
### JSON adapter
61+
If you do not want pagination links to be automatically rendered, you may disable it by setting the `ActiveModelSerializers.config.collection_serializer` config to
62+
`ActiveModel::Serializer::NonPaginatedCollectionSerializer`.
7463

75-
If you are using `JSON` adapter, pagination links will not be included automatically, but it is possible to do so using `meta` key.
64+
If you want to disable pagination links for a specific controller, you may set the `serializer` option to `ActiveModel::Serializer::NonPaginatedCollectionSerializer`:
7665

77-
Add this method to your base API controller.
78-
79-
```ruby
80-
def pagination_dict(object)
81-
{
82-
current_page: object.current_page,
83-
next_page: object.next_page,
84-
prev_page: object.prev_page,
85-
total_pages: object.total_pages,
86-
total_count: object.total_count
87-
}
66+
``` ruby
67+
class PostsController < ApplicationController
68+
def index
69+
posts = Post.page(params[:page]).per_page(params[:per_page])
70+
render json: posts, serializer: ActiveModel::Serializer::NonPaginatedCollectionSerializer
71+
end
8872
end
8973
```
9074

91-
Then, use it on your render method.
75+
### Json adapter
76+
77+
If you are using the `Json` adapter, pagination links will not be included automatically, but it is possible to handle pagination using the `meta` option:
9278

9379
```ruby
94-
render json: posts, meta: pagination_dict(posts)
80+
class PostsController < ApplicationController
81+
def index
82+
posts = Post.page(params[:page]).per_page(params[:per_page])
83+
render json: posts, meta: pagination_dict(posts)
84+
end
85+
86+
private
87+
88+
def pagination_dict(object)
89+
{
90+
current_page: object.current_page,
91+
next_page: object.next_page,
92+
prev_page: object.prev_page,
93+
total_pages: object.total_pages,
94+
total_count: object.total_count
95+
}
96+
end
97+
end
9598
```
9699

97-
ex.
100+
The response might look like:
98101
```json
99102
{
100103
"posts": [
@@ -113,27 +116,3 @@ ex.
113116
}
114117
}
115118
```
116-
117-
You can also achieve the same result if you have a helper method that adds the pagination info in the meta tag. For instance, in your action specify a custom serializer.
118-
119-
```ruby
120-
render json: @posts, each_serializer: PostPreviewSerializer, meta: meta_attributes(@post)
121-
```
122-
123-
```ruby
124-
#expects pagination!
125-
def meta_attributes(resource, extra_meta = {})
126-
{
127-
current_page: resource.current_page,
128-
next_page: resource.next_page,
129-
prev_page: resource.prev_page,
130-
total_pages: resource.total_pages,
131-
total_count: resource.total_count
132-
}.merge(extra_meta)
133-
end
134-
```
135-
136-
137-
### Attributes adapter
138-
139-
This adapter does not allow us to use `meta` key, due to that it is not possible to add pagination links.

lib/active_model/serializable_resource.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
require 'active_model_serializers/adapter'
33
module ActiveModel
44
class SerializableResource
5-
ADAPTER_OPTION_KEYS = Set.new([:include, :fields, :adapter, :meta, :meta_key, :links])
5+
ADAPTER_OPTION_KEYS = Set.new([:include, :fields, :adapter, :meta, :meta_key, :links, :serialization_context])
66
include ActiveModelSerializers::Logging
77

88
delegate :serializable_hash, :as_json, :to_json, to: :adapter

lib/active_model/serializer.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
require 'thread_safe'
22
require 'active_model/serializer/collection_serializer'
3+
require 'active_model/serializer/non_paginated_collection_serializer'
34
require 'active_model/serializer/array_serializer'
45
require 'active_model/serializer/error_serializer'
56
require 'active_model/serializer/errors_serializer'

lib/active_model/serializer/collection_serializer.rb

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,7 @@ def json_key
3232

3333
def paginated?
3434
object.respond_to?(:current_page) &&
35-
object.respond_to?(:total_pages) &&
36-
object.respond_to?(:size)
35+
object.respond_to?(:total_pages)
3736
end
3837

3938
protected
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
require 'active_model/serializer/collection_serializer'
2+
3+
module ActiveModel
4+
class Serializer
5+
class NonPaginatedCollectionSerializer < CollectionSerializer
6+
def paginated?
7+
false
8+
end
9+
end
10+
end
11+
end

lib/active_model/serializer/reflection.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ def initialize(*)
3838
super
3939
@_links = {}
4040
@_include_data = true
41+
@_meta = nil
4142
end
4243

4344
def link(name, value = nil, &block)

lib/active_model_serializers/adapter/json_api.rb

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
# coding: utf-8
12
# {http://jsonapi.org/format/ JSON API specification}
23
# rubocop:disable Style/AsciiComments
34
# TODO: implement!
@@ -35,6 +36,7 @@ def initialize(serializer, options = {})
3536
super
3637
@include_tree = ActiveModel::Serializer::IncludeTree.from_include_args(options[:include])
3738
@fieldset = options[:fieldset] || ActiveModel::Serializer::Fieldset.new(options.delete(:fields))
39+
@serialization_context = options[:serialization_context]
3840
end
3941

4042
def default_key_transform
@@ -126,7 +128,7 @@ def success_document(options)
126128
hash[:links].update(instance_options[:links])
127129
end
128130

129-
if is_collection && serializer.paginated?
131+
if paginate?
130132
hash[:links] ||= {}
131133
hash[:links].update(pagination_links_for(serializer, options))
132134
end
@@ -185,7 +187,7 @@ def fragment_cache(cached_hash, non_cached_hash)
185187

186188
protected
187189

188-
attr_reader :fieldset
190+
attr_reader :fieldset, :serialization_context
189191

190192
private
191193

@@ -234,6 +236,12 @@ def resource_objects_for(serializers)
234236
[@primary, @included]
235237
end
236238

239+
def paginate?
240+
!serialization_context.nil? &&
241+
serializer.respond_to?(:paginated?) &&
242+
serializer.paginated?
243+
end
244+
237245
def process_resource(serializer, primary)
238246
resource_identifier = ResourceIdentifier.new(serializer).as_json
239247
return false unless @resource_identifiers.add?(resource_identifier)
@@ -499,7 +507,7 @@ def links_for(serializer)
499507
# prs:
500508
# https://github.com/rails-api/active_model_serializers/pull/1041
501509
def pagination_links_for(serializer, options)
502-
PaginationLinks.new(serializer.object, options[:serialization_context]).serializable_hash(options)
510+
PaginationLinks.new(serializer.object, serialization_context).serializable_hash(options)
503511
end
504512

505513
# {http://jsonapi.org/format/#document-meta Docment Meta}

0 commit comments

Comments
 (0)