diff --git a/lib/active_model_serializers/adapter/json_api/pagination_links.rb b/lib/active_model_serializers/adapter/json_api/pagination_links.rb index b15f5ba6..859368b0 100644 --- a/lib/active_model_serializers/adapter/json_api/pagination_links.rb +++ b/lib/active_model_serializers/adapter/json_api/pagination_links.rb @@ -15,17 +15,18 @@ module ActiveModelSerializers 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 @@ -34,25 +35,39 @@ module ActiveModelSerializers private - def pages_from - return {} if collection.total_pages <= FIRST_PAGE + def location_url + url_for_page(collection.current_page) + end - {}.tap do |pages| - pages[:self] = collection.current_page + def first_page_url + url_for_page(1) + end - unless collection.current_page == FIRST_PAGE - pages[:first] = FIRST_PAGE - pages[:prev] = collection.current_page - FIRST_PAGE - 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 @@ -63,6 +78,10 @@ module ActiveModelSerializers 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 diff --git a/test/action_controller/json_api/pagination_test.rb b/test/action_controller/json_api/pagination_test.rb index 0af086b7..98355a05 100644 --- a/test/action_controller/json_api/pagination_test.rb +++ b/test/action_controller/json_api/pagination_test.rb @@ -58,8 +58,10 @@ module ActionController 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 } } @@ -78,17 +80,21 @@ module ActionController 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' } @@ -96,10 +102,12 @@ module ActionController 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'] diff --git a/test/adapter/json_api/pagination_links_test.rb b/test/adapter/json_api/pagination_links_test.rb index 736ea2fe..3cdbab0e 100644 --- a/test/adapter/json_api/pagination_links_test.rb +++ b/test/adapter/json_api/pagination_links_test.rb @@ -54,6 +54,16 @@ module ActiveModelSerializers } 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: { @@ -71,7 +81,9 @@ module ActiveModelSerializers 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 @@ -108,10 +120,10 @@ module ActiveModelSerializers 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 @@ -139,7 +151,7 @@ module ActiveModelSerializers 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 @@ -147,7 +159,7 @@ module ActiveModelSerializers 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