class JsonApiServer::Pagination

Description

JSON API Spec: jsonapi.org/format/#fetching-pagination - “Pagination links MUST appear in the links object that corresponds to a collection. To paginate the primary data, supply pagination links in the top-level links object.”

This class handles pagination. It (1) ensures page[number] is a positive integer, (2) page[limit] doesn't exceed a maximum value and (3) generates a pagination sub-query (to be merged into a master query). It uses the WillPaginate gem rubygems.org/gems/will_paginate/versions/3.1.6.

Usage:

A paginating request will look like:

/comments?page[number]=1&page[limit]=10

Where:

The class takes an ActiveDispatch::Request object, an ActiveRecord::Base model (to generate a pagination sub-query) and two options:

:max_per_page - maximum number of records per page which defaults to JsonApiServer::Configuration#default_max_per_page.

:default_per_page - number of records to show if not specified in page[limit] defaults to JsonApiServer::Configuration#default_per_page).

Example:

Create an instance in your controller:

pagination = JsonApiServer::Pagination.new(request, Comment, max_per_page: 50, default_per_page: 10)

Merge pagination sub-query into your ActiveRecord query:

recent_comments = Comment.recent.merge(pagination.query)

Get JsonApiServer::Paginator instance to create links in your JSON serializer:

paginator = pagination.paginator_for(recent_comments)
paginator.as_json # creates JSON API links

Pass paginator as param to a class inheriting from JsonApiServer::ResourcesSerializer and it creates the links section for you.

class CommentsSerializer < JsonApiServer::ResourcesSerializer
  serializer CommentSerializer
end
 serializer = CommentsSerializer.new(recent_comments, paginator: paginator)

Note:

JsonApiServer::Builder class provides an easier way to use this class.

Attributes

default_per_page[R]

Default number of records to show per page. If page[limit] is not present, it will use this value. If this is not set, it will use JsonApiServer.configuration.default_per_page.

max_per_page[R]

Maximum records per page. Prevents users from requesting too many records. Passed into constructor.

model[R]

ActiveRecord::Base model passed in constructor.

params[R]

Query parameters from request.

request[R]

ActionDispatch::Request passed in constructor.

Public Class Methods

default_max_per_page() click to toggle source

Default max per page. Defaults to JsonApiServer.configuration.default_max_per_page

# File lib/json_api_server/pagination.rb, line 110
def default_max_per_page
  JsonApiServer.configuration.default_max_per_page
end
default_per_page() click to toggle source

Default per page. Defaults to JsonApiServer.configuration.default_per_page.

# File lib/json_api_server/pagination.rb, line 115
def default_per_page
  JsonApiServer.configuration.default_per_page
end
new(request, model, **options) click to toggle source

Arguments:

  • request - ActionDispatch::Request

  • model - ActiveRecord::Base model. Used to generate sub-query.

  • options - (Hash)

    • :max_per_page (Integer) - Optional. Defaults to JsonApiServer.configuration.default_max_per_page.

    • :default_per_page (Integer) - Optional. Defaults to JsonApiServer.configuration.default_per_page.

# File lib/json_api_server/pagination.rb, line 85
def initialize(request, model, **options)
  @request = request
  @model = model
  @max_per_page = (options[:max_per_page] || self.class.default_max_per_page).to_i
  @default_per_page = (options[:default_per_page] || self.class.default_per_page).to_i
  @params = request.query_parameters
end

Public Instance Methods

base_url() click to toggle source

Joins JsonApiServer::Configuration#base_url with request.path.

# File lib/json_api_server/pagination.rb, line 167
def base_url
  @base_url ||= File.join(JsonApiServer.configuration.base_url, request.path)
end
limit()
Alias for: per_page
number()
Alias for: page
page() click to toggle source

The current page number. From query parameter page</tt>.

# File lib/json_api_server/pagination.rb, line 153
def page
  @page ||= begin
    n = begin
          params[:page][:number].to_i
        rescue
          1
        end
    n <= 0 ? 1 : n
  end
end
Also aliased as: number
paginator_for(collection, options = {}) click to toggle source

Create an instance of JsonApiServer::Paginator for a WillPaginate collection. Returns nil if not a WillPaginate collection.

params:

  • collection (WillPaginate collection) - i.e., Comment.recent.paginate(page: x, per_page: y)

  • options (Hash):

  • per_page (Integer) - defaults to self.per_page.

  • base_url (String) - defaults to self.base_url (joins JsonApiServer.configuration.base_url with request.path).

# File lib/json_api_server/pagination.rb, line 128
def paginator_for(collection, options = {})
  if collection.respond_to?(:current_page) && collection.respond_to?(:total_pages)
    # call to_i on WillPaginate::PageNumber which DelegateClass(Integer)
    # paginator(collection.current_page.to_i, collection.total_pages.to_i, options)
    # HACK: collection.current_page.to_i disappears when merged? works w/o merge.
    paginator(page, collection.total_pages.to_i, options)
  end
end
per_page() click to toggle source

Number of records per page. From query parameter page[limit].

# File lib/json_api_server/pagination.rb, line 138
def per_page
  @per_page ||= begin
    l = begin
          params[:page][:limit].to_i
        rescue
          default_per_page
        end
    l = [max_per_page, l].min
    l <= 0 ? default_per_page : l
  end
end
Also aliased as: limit
query()
Alias for: relation
relation() click to toggle source

Calls WillPaginate 'paginate' method with page and per_page. Returns an ActiveRecord::Relation object (a query fragment) which can be merged into another query with merge.

Example:

pagination = JsonApiServer::Pagination.new(request, Comment, options)
recent_comments = Comment.recent.merge(pagination.relation)
# File lib/json_api_server/pagination.rb, line 102
def relation
  @relation ||= model.paginate(page: page, per_page: per_page)
end
Also aliased as: query

Protected Instance Methods

paginator(current_page, total_pages, options = {}) click to toggle source

Creates an instance of JsonApiServer::Paginator.

params:

  • current_page (Integer)

  • total_pages (Integer)

  • options (Hash):

  • per_page (Integer) - defaults to self.per_page.

  • base_url (String) - defaults to self.base_url (joins

    JsonApiServer::Configuration#base_url with request.path.).
    
# File lib/json_api_server/pagination.rb, line 182
def paginator(current_page, total_pages, options = {})
  per_page = options[:per_page] || self.per_page
  base_url = options[:base_url] || self.base_url
  JsonApiServer.paginator(current_page, total_pages, per_page,
                          base_url, params)
end