module JSONAPI::Pagination

Pagination support

Constants

JSONAPI_PAGE_SIZE

Default number of items per page.

Private Instance Methods

jsonapi_page_size(pagination_params) click to toggle source

Retrieves the default page size

@param per_page_param [Hash] opts the paginations params @option opts [String] :number the page number requested @option opts [String] :size the page size requested

@return [Integer]

# File lib/jsonapi/pagination.rb, line 112
def jsonapi_page_size(pagination_params)
  per_page = pagination_params[:size].to_f.to_i

  return self.class
          .const_get(:JSONAPI_PAGE_SIZE)
          .to_i if per_page < 1

  per_page
end
jsonapi_paginate(resources) { |resources| ... } click to toggle source

Applies pagination to a set of resources

Ex.: `GET /resource?page=2&page=10`

@return [ActiveRecord::Base] a collection of resources

# File lib/jsonapi/pagination.rb, line 13
def jsonapi_paginate(resources)
  offset, limit, _ = jsonapi_pagination_params

  if resources.respond_to?(:offset)
    resources = resources.offset(offset).limit(limit)
  else
    original_size = resources.size
    resources = resources[(offset)..(offset + limit - 1)] || []

    # Cache the original resources size to be used for pagination meta
    resources.instance_variable_set(:@original_size, original_size)
  end

  block_given? ? yield(resources) : resources
end
jsonapi_pagination(resources) click to toggle source

Generates the pagination links

@return [Array]

# File lib/jsonapi/pagination.rb, line 32
def jsonapi_pagination(resources)
  links = { self: request.base_url + request.fullpath }
  pagination = jsonapi_pagination_meta(resources)

  return links if pagination.blank?

  original_params = params.except(
    *jsonapi_path_parameters.keys.map(&:to_s)
  ).as_json.with_indifferent_access

  original_params[:page] = original_params[:page].dup || {}
  original_url = request.base_url + request.path + '?'

  pagination.each do |page_name, number|
    next if page_name == :records

    original_params[:page][:number] = number
    links[page_name] = original_url + CGI.unescape(
      original_params.to_query
    )
  end

  links
end
jsonapi_pagination_meta(resources) click to toggle source

Generates pagination numbers

@return [Hash] with the first, previous, next, current, last page numbers

# File lib/jsonapi/pagination.rb, line 60
def jsonapi_pagination_meta(resources)
  return {} unless JSONAPI::Rails.is_collection?(resources)

  _, limit, page = jsonapi_pagination_params

  numbers = { current: page }

  if resources.respond_to?(:unscope)
    total = resources.unscope(:limit, :offset, :order).size
  else
    # Try to fetch the cached size first
    total = resources.instance_variable_get(:@original_size)
    total ||= resources.size
  end

  last_page = [1, (total.to_f / limit).ceil].max

  if page > 1
    numbers[:first] = 1
    numbers[:prev] = page - 1
  end

  if page < last_page
    numbers[:next] = page + 1
    numbers[:last] = last_page
  end

  if total.present?
    numbers[:records] = total
  end

  numbers
end
jsonapi_pagination_params() click to toggle source

Extracts the pagination params

@return [Array] with the offset, limit and the current page number

# File lib/jsonapi/pagination.rb, line 97
def jsonapi_pagination_params
  pagination = params[:page].try(:slice, :number, :size) || {}
  per_page = jsonapi_page_size(pagination)
  num = [1, pagination[:number].to_f.to_i].max

  [(num - 1) * per_page, per_page, num]
end
jsonapi_path_parameters() click to toggle source

Fallback to Rack's parsed query string when Rails is not available

@return [Hash]

# File lib/jsonapi/pagination.rb, line 125
def jsonapi_path_parameters
  return request.path_parameters if request.respond_to?(:path_parameters)

  request.send(:parse_query, request.query_string, '&;')
end