Class: JsonApiServer::Pagination

Inherits:
Object
  • Object
show all
Defined in:
lib/json_api_server/pagination.rb

Overview

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:

  • page[number] is the current page

  • page[limit] is number of records per page

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.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(request, model, **options) ⇒ Pagination

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.



85
86
87
88
89
90
91
# 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

Instance Attribute Details

#default_per_pageObject (readonly)

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.



76
77
78
# File 'lib/json_api_server/pagination.rb', line 76

def default_per_page
  @default_per_page
end

#max_per_pageObject (readonly)

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



71
72
73
# File 'lib/json_api_server/pagination.rb', line 71

def max_per_page
  @max_per_page
end

#modelObject (readonly)

ActiveRecord::Base model passed in constructor.



64
65
66
# File 'lib/json_api_server/pagination.rb', line 64

def model
  @model
end

#paramsObject (readonly)

Query parameters from #request.



67
68
69
# File 'lib/json_api_server/pagination.rb', line 67

def params
  @params
end

#requestObject (readonly)

ActionDispatch::Request passed in constructor.



61
62
63
# File 'lib/json_api_server/pagination.rb', line 61

def request
  @request
end

Class Method Details

.default_max_per_pageObject

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



110
111
112
# File 'lib/json_api_server/pagination.rb', line 110

def default_max_per_page
  JsonApiServer.configuration.default_max_per_page
end

.default_per_pageObject

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



115
116
117
# File 'lib/json_api_server/pagination.rb', line 115

def default_per_page
  JsonApiServer.configuration.default_per_page
end

Instance Method Details

#base_urlObject

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



167
168
169
# File 'lib/json_api_server/pagination.rb', line 167

def base_url
  @base_url ||= File.join(JsonApiServer.configuration.base_url, request.path)
end

#pageObject Also known as: number

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



153
154
155
156
157
158
159
160
161
162
# 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

#paginator_for(collection, options = {}) ⇒ Object

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).



128
129
130
131
132
133
134
135
# 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_pageObject Also known as: limit

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



138
139
140
141
142
143
144
145
146
147
148
# 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

#relationObject Also known as: query

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)


102
103
104
# File 'lib/json_api_server/pagination.rb', line 102

def relation
  @relation ||= model.paginate(page: page, per_page: per_page)
end