Add pagination links automatically

Pagination links will be included in your response automatically as long
as the resource is paginated using Kaminari or WillPaginate
and if you are using a JSON-API adapter. The others adapters does not have this feature.
This commit is contained in:
Bruno Bacarini 2015-08-17 14:25:59 -03:00
parent a41d90cce4
commit 2c2f948fa0
8 changed files with 52 additions and 47 deletions

View File

@ -118,7 +118,7 @@ If you wish to use a serializer other than the default, you can explicitly pass
render json: @posts, each_serializer: PostPreviewSerializer render json: @posts, each_serializer: PostPreviewSerializer
# Or, you can explicitly provide the collection serializer as well # Or, you can explicitly provide the collection serializer as well
render json: @posts, serializer: PaginatedSerializer, each_serializer: PostPreviewSerializer render json: @posts, serializer: CollectionSerializer, each_serializer: PostPreviewSerializer
``` ```
### Meta ### Meta
@ -272,6 +272,11 @@ And you can change the JSON key that the serializer should use for a particular
The `url` declaration describes which named routes to use while generating URLs The `url` declaration describes which named routes to use while generating URLs
for your JSON. Not every adapter will require URLs. for your JSON. Not every adapter will require URLs.
## Pagination
Pagination links will be included in your response automatically as long as the resource is paginated using [Kaminari](https://github.com/amatsuda/kaminari) or [WillPaginate](https://github.com/mislav/will_paginate) and if you are using a ```JSON-API``` adapter. The others adapters does not have this feature.
For more information about it, please see in our docs [How to add pagination links](https://github.com/rails-api/active_model_serializers/blob/master/docs/howto/add_pagination_links.md)
## Caching ## Caching

View File

@ -1,15 +1,19 @@
# How to add pagination links # How to add pagination links
If you want pagination links in your response, specify it in the `render` Pagination links will be included in your response automatically as long as the resource is paginated and if you are using a ```JSON-API``` adapter. The others adapters does not have this feature.
If you want pagination links in your response, use [Kaminari](https://github.com/amatsuda/kaminari) or [WillPaginate](https://github.com/mislav/will_paginate).
```ruby ```ruby
render json: @posts, pagination: true #kaminari example
@posts = Kaminari.paginate_array(Post.all).page(3).per(1)
render json: @posts
#will_paginate example
@posts = Post.all.paginate(page: 3, per_page: 1)
render json: @posts
``` ```
AMS relies on either `Kaminari` or `WillPaginate`. Please install either dependency by adding one of those to your Gemfile.
Pagination links will only be included in your response if you are using a ```JSON-API``` adapter, the others adapters doesn't have this feature.
```ruby ```ruby
ActiveModel::Serializer.config.adapter = :json_api ActiveModel::Serializer.config.adapter = :json_api
``` ```
@ -38,3 +42,5 @@ ex:
} }
} }
``` ```
AMS relies on either [Kaminari](https://github.com/amatsuda/kaminari) or [WillPaginate](https://github.com/mislav/will_paginate). Please install either dependency by adding one of those to your Gemfile.

View File

@ -25,9 +25,10 @@ module ActionController
"Please pass 'adapter: false' or see ActiveSupport::SerializableResource#serialize" "Please pass 'adapter: false' or see ActiveSupport::SerializableResource#serialize"
options[:adapter] = false options[:adapter] = false
end end
if options[:pagination] if resource.respond_to?(:current_page) && resource.respond_to?(:total_pages)
options[:original_url] = original_url options[:pagination] = {}
options[:query_parameters] = query_parameters options[:pagination][:original_url] = original_url
options[:pagination][:query_parameters] = query_parameters
end end
ActiveModel::SerializableResource.serialize(resource, options) do |serializable_resource| ActiveModel::SerializableResource.serialize(resource, options) do |serializable_resource|
if serializable_resource.serializer? if serializable_resource.serializer?

View File

@ -2,7 +2,7 @@ require "set"
module ActiveModel module ActiveModel
class SerializableResource class SerializableResource
ADAPTER_OPTION_KEYS = Set.new([:include, :fields, :adapter, :pagination]) ADAPTER_OPTION_KEYS = Set.new([:include, :fields, :adapter])
def initialize(resource, options = {}) def initialize(resource, options = {})
@resource = resource @resource = resource

View File

@ -164,7 +164,7 @@ module ActiveModel
def add_links(options) def add_links(options)
links = @hash.fetch(:links) { {} } links = @hash.fetch(:links) { {} }
resources = serializer.instance_variable_get(:@resource) resources = serializer.instance_variable_get(:@resource)
@hash[:links] = add_pagination_links(links, resources, options) if @options[:pagination] @hash[:links] = add_pagination_links(links, resources, options) if options[:pagination]
end end
def add_pagination_links(links, resources, options) def add_pagination_links(links, resources, options)

View File

@ -14,7 +14,7 @@ module ActiveModel
def serializable_hash(options = {}) def serializable_hash(options = {})
pages_from.each_with_object({}) do |(key, value), hash| pages_from.each_with_object({}) do |(key, value), hash|
query_parameters = options.fetch(:query_parameters) { {} } query_parameters = options[:pagination].fetch(:query_parameters) { {} }
params = query_parameters.merge(page: { number: value, size: collection.size }).to_query params = query_parameters.merge(page: { number: value, size: collection.size }).to_query
hash[key] = "#{url(options)}?#{params}" hash[key] = "#{url(options)}?#{params}"
@ -51,7 +51,7 @@ module ActiveModel
def url(options) def url(options)
self_link = options.fetch(:links) {{}} self_link = options.fetch(:links) {{}}
self_link.fetch(:self) {} ? options[:links][:self] : options[:original_url] self_link.fetch(:self) {} ? options[:links][:self] : options[:pagination][:original_url]
end end
end end
end end

View File

@ -31,19 +31,16 @@ module ActionController
end end
def render_pagination_using_kaminari def render_pagination_using_kaminari
render json: using_kaminari, adapter: :json_api, pagination: true render json: using_kaminari, adapter: :json_api
end end
def render_pagination_using_will_paginate def render_pagination_using_will_paginate
render json: using_will_paginate, adapter: :json_api, pagination: true render json: using_will_paginate, adapter: :json_api
end end
def render_array_without_pagination_links def render_array_without_pagination_links
render json: using_will_paginate, adapter: :json_api, pagination: false setup
end render json: @array, adapter: :json_api
def render_array_omitting_pagination_options
render json: using_kaminari, adapter: :json_api
end end
end end
@ -104,12 +101,6 @@ module ActionController
response = JSON.parse(@response.body) response = JSON.parse(@response.body)
refute response.key? 'links' refute response.key? 'links'
end end
def test_array_omitting_pagination_options
get :render_array_omitting_pagination_options, page: { number: 2, size: 1 }
response = JSON.parse(@response.body)
refute response.key? 'links'
end
end end
end end
end end

View File

@ -27,15 +27,11 @@ module ActiveModel
end end
def data def data
{ { data:[
data: [{ { id:"1", type:"profiles", attributes:{name:"Name 1", description:"Description 1" } },
id:"2", { id:"2", type:"profiles", attributes:{name:"Name 2", description:"Description 2" } },
type:"profiles", { id:"3", type:"profiles", attributes:{name:"Name 3", description:"Description 3" } }
attributes:{ ]
name:"Name 2",
description:"Description 2"
}
}]
} }
end end
@ -56,42 +52,48 @@ module ActiveModel
end end
def expected_response_with_pagination_links def expected_response_with_pagination_links
data.merge links {}.tap do |hash|
hash[:data] = [data.values.flatten.second]
hash.merge! links
end
end end
def expected_response_with_pagination_links_and_additional_params def expected_response_with_pagination_links_and_additional_params
new_links = links[:links].each_with_object({}) {|(key, value), hash| hash[key] = "#{value}&teste=teste" } new_links = links[:links].each_with_object({}) {|(key, value), hash| hash[key] = "#{value}&teste=teste" }
data.merge links: new_links {}.tap do |hash|
hash[:data] = [data.values.flatten.second]
hash.merge! links: new_links
end
end end
def test_pagination_links_using_kaminari def test_pagination_links_using_kaminari
serializer = ArraySerializer.new(using_kaminari) serializer = ArraySerializer.new(using_kaminari)
adapter = ActiveModel::Serializer::Adapter::JsonApi.new(serializer, pagination: true) adapter = ActiveModel::Serializer::Adapter::JsonApi.new(serializer)
assert_equal expected_response_with_pagination_links, assert_equal expected_response_with_pagination_links,
adapter.serializable_hash(original_url: "http://example.com") adapter.serializable_hash(pagination: { original_url: "http://example.com" })
end end
def test_pagination_links_using_will_paginate def test_pagination_links_using_will_paginate
serializer = ArraySerializer.new(using_will_paginate) serializer = ArraySerializer.new(using_will_paginate)
adapter = ActiveModel::Serializer::Adapter::JsonApi.new(serializer, pagination: true) adapter = ActiveModel::Serializer::Adapter::JsonApi.new(serializer)
assert_equal expected_response_with_pagination_links, assert_equal expected_response_with_pagination_links,
adapter.serializable_hash(original_url: "http://example.com") adapter.serializable_hash(pagination: { original_url: "http://example.com" })
end end
def test_pagination_links_with_additional_params def test_pagination_links_with_additional_params
serializer = ArraySerializer.new(using_will_paginate) serializer = ArraySerializer.new(using_will_paginate)
adapter = ActiveModel::Serializer::Adapter::JsonApi.new(serializer, pagination: true) adapter = ActiveModel::Serializer::Adapter::JsonApi.new(serializer)
assert_equal expected_response_with_pagination_links_and_additional_params, assert_equal expected_response_with_pagination_links_and_additional_params,
adapter.serializable_hash(original_url: "http://example.com", adapter.serializable_hash(pagination: { original_url: "http://example.com",
query_parameters: { teste: "teste"}) query_parameters: { teste: "teste"}})
end end
def test_not_showing_pagination_links def test_not_showing_pagination_links
serializer = ArraySerializer.new(using_will_paginate) serializer = ArraySerializer.new(@array)
adapter = ActiveModel::Serializer::Adapter::JsonApi.new(serializer, pagination: false) adapter = ActiveModel::Serializer::Adapter::JsonApi.new(serializer)
assert_equal expected_response_without_pagination_links, adapter.serializable_hash assert_equal expected_response_without_pagination_links, adapter.serializable_hash
end end