Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Always include self, first, last pagination links #2149

Merged
61 changes: 40 additions & 21 deletions lib/active_model_serializers/adapter/json_api/pagination_links.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,18 @@ def initialize(collection, adapter_options)
JsonApi::PaginationLinks requires a ActiveModelSerializers::SerializationContext.
Please pass a ':serialization_context' option or
override CollectionSerializer#paginated? to return 'false'.
EOF
EOF
end
end

def as_json
per_page = collection.try(:per_page) || collection.try(:limit_value) || collection.size
pages_from.each_with_object({}) do |(key, value), hash|
params = query_parameters.merge(page: { number: value, size: per_page }).to_query

hash[key] = "#{url(adapter_options)}?#{params}"
end
{
self: location_url,
first: first_page_url,
prev: prev_page_url,
next: next_page_url,
last: last_page_url
}
end

protected
Expand All @@ -34,25 +35,39 @@ def as_json

private

def pages_from
return {} if collection.total_pages <= FIRST_PAGE

{}.tap do |pages|
pages[:self] = collection.current_page
def location_url
url_for_page(collection.current_page)
end

unless collection.current_page == FIRST_PAGE
pages[:first] = FIRST_PAGE
pages[:prev] = collection.current_page - FIRST_PAGE
end
def first_page_url
url_for_page(1)
end

unless collection.current_page == collection.total_pages
pages[:next] = collection.current_page + FIRST_PAGE
pages[:last] = collection.total_pages
end
def last_page_url
if collection.total_pages == 0
url_for_page(FIRST_PAGE)
else
url_for_page(collection.total_pages)
end
end

def url(options)
def prev_page_url
return nil if collection.current_page == FIRST_PAGE
url_for_page(collection.current_page - FIRST_PAGE)
end

def next_page_url
return nil if collection.total_pages == 0 || collection.current_page == collection.total_pages
url_for_page(collection.next_page)
end

def url_for_page(number)
params = query_parameters.dup
params[:page] = { size: per_page, number: number }
"#{url(adapter_options)}?#{params.to_query}"
end

def url(options = {})
@url ||= options.fetch(:links, {}).fetch(:self, nil) || request_url
end

Expand All @@ -63,6 +78,10 @@ def request_url
def query_parameters
@query_parameters ||= context.query_parameters
end

def per_page
@per_page ||= collection.try(:per_page) || collection.try(:limit_value) || collection.size
end
end
end
end
Expand Down
20 changes: 14 additions & 6 deletions test/action_controller/json_api/pagination_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,10 @@ def test_render_pagination_links_with_will_paginate
assert_equal expected_links, response['links']
end

def test_render_only_last_and_next_pagination_links
def test_render_only_first_last_and_next_pagination_links
expected_links = { 'self' => "#{WILL_PAGINATE_URI}?page%5Bnumber%5D=1&page%5Bsize%5D=2",
'first' => "#{WILL_PAGINATE_URI}?page%5Bnumber%5D=1&page%5Bsize%5D=2",
'prev' => nil,
'next' => "#{WILL_PAGINATE_URI}?page%5Bnumber%5D=2&page%5Bsize%5D=2",
'last' => "#{WILL_PAGINATE_URI}?page%5Bnumber%5D=2&page%5Bsize%5D=2" }
get :render_pagination_using_will_paginate, params: { page: { number: 1, size: 2 } }
Expand All @@ -78,28 +80,34 @@ def test_render_pagination_links_with_kaminari
assert_equal expected_links, response['links']
end

def test_render_only_prev_and_first_pagination_links
def test_render_only_prev_first_and_last_pagination_links
expected_links = { 'self' => "#{KAMINARI_URI}?page%5Bnumber%5D=3&page%5Bsize%5D=1",
'first' => "#{KAMINARI_URI}?page%5Bnumber%5D=1&page%5Bsize%5D=1",
'prev' => "#{KAMINARI_URI}?page%5Bnumber%5D=2&page%5Bsize%5D=1" }
'prev' => "#{KAMINARI_URI}?page%5Bnumber%5D=2&page%5Bsize%5D=1",
'next' => nil,
'last' => "#{KAMINARI_URI}?page%5Bnumber%5D=3&page%5Bsize%5D=1" }
get :render_pagination_using_kaminari, params: { page: { number: 3, size: 1 } }
response = JSON.parse(@response.body)
assert_equal expected_links, response['links']
end

def test_render_only_last_and_next_pagination_links_with_additional_params
def test_render_only_first_last_and_next_pagination_links_with_additional_params
expected_links = { 'self' => "#{WILL_PAGINATE_URI}?page%5Bnumber%5D=1&page%5Bsize%5D=2&teste=additional",
'first' => "#{WILL_PAGINATE_URI}?page%5Bnumber%5D=1&page%5Bsize%5D=2&teste=additional",
'prev' => nil,
'next' => "#{WILL_PAGINATE_URI}?page%5Bnumber%5D=2&page%5Bsize%5D=2&teste=additional",
'last' => "#{WILL_PAGINATE_URI}?page%5Bnumber%5D=2&page%5Bsize%5D=2&teste=additional" }
get :render_pagination_using_will_paginate, params: { page: { number: 1, size: 2 }, teste: 'additional' }
response = JSON.parse(@response.body)
assert_equal expected_links, response['links']
end

def test_render_only_prev_and_first_pagination_links_with_additional_params
def test_render_only_prev_first_and_last_pagination_links_with_additional_params
expected_links = { 'self' => "#{KAMINARI_URI}?page%5Bnumber%5D=3&page%5Bsize%5D=1&teste=additional",
'first' => "#{KAMINARI_URI}?page%5Bnumber%5D=1&page%5Bsize%5D=1&teste=additional",
'prev' => "#{KAMINARI_URI}?page%5Bnumber%5D=2&page%5Bsize%5D=1&teste=additional" }
'prev' => "#{KAMINARI_URI}?page%5Bnumber%5D=2&page%5Bsize%5D=1&teste=additional",
'next' => nil,
'last' => "#{KAMINARI_URI}?page%5Bnumber%5D=3&page%5Bsize%5D=1&teste=additional" }
get :render_pagination_using_kaminari, params: { page: { number: 3, size: 1 }, teste: 'additional' }
response = JSON.parse(@response.body)
assert_equal expected_links, response['links']
Expand Down
22 changes: 17 additions & 5 deletions test/adapter/json_api/pagination_links_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,16 @@ def data
}
end

def empty_collection_links
{
self: "#{URI}?page%5Bnumber%5D=1&page%5Bsize%5D=2",
first: "#{URI}?page%5Bnumber%5D=1&page%5Bsize%5D=2",
prev: nil,
next: nil,
last: "#{URI}?page%5Bnumber%5D=1&page%5Bsize%5D=2"
}
end

def links
{
links: {
Expand All @@ -71,7 +81,9 @@ def last_page_links
links: {
self: "#{URI}?page%5Bnumber%5D=3&page%5Bsize%5D=2",
first: "#{URI}?page%5Bnumber%5D=1&page%5Bsize%5D=2",
prev: "#{URI}?page%5Bnumber%5D=2&page%5Bsize%5D=2"
prev: "#{URI}?page%5Bnumber%5D=2&page%5Bsize%5D=2",
next: nil,
last: "#{URI}?page%5Bnumber%5D=3&page%5Bsize%5D=2"
}
}
end
Expand Down Expand Up @@ -108,10 +120,10 @@ def expected_response_with_last_page_pagination_links
end
end

def expected_response_with_no_data_pagination_links
def expected_response_with_empty_collection_pagination_links
{}.tap do |hash|
hash[:data] = []
hash[:links] = {}
hash.merge! links: empty_collection_links
end
end

Expand Down Expand Up @@ -139,15 +151,15 @@ def test_pagination_links_when_zero_results_kaminari

adapter = load_adapter(using_kaminari(1), mock_request)

assert_equal expected_response_with_no_data_pagination_links, adapter.serializable_hash
assert_equal expected_response_with_empty_collection_pagination_links, adapter.serializable_hash
end

def test_pagination_links_when_zero_results_will_paginate
@array = []

adapter = load_adapter(using_will_paginate(1), mock_request)

assert_equal expected_response_with_no_data_pagination_links, adapter.serializable_hash
assert_equal expected_response_with_empty_collection_pagination_links, adapter.serializable_hash
end

def test_last_page_pagination_links_using_kaminari
Expand Down