-
Notifications
You must be signed in to change notification settings - Fork 61
/
Copy pathpagination.rb
124 lines (97 loc) · 3.32 KB
/
pagination.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
module JSONAPI
# Pagination support
module Pagination
private
# Default number of items per page.
JSONAPI_PAGE_SIZE = 30
# Applies pagination to a set of resources
#
# Ex.: `GET /resource?page[number]=2&page[size]=10`
#
# @return [ActiveRecord::Base] a collection of resources
def jsonapi_paginate(resources)
offset, limit, _ = jsonapi_pagination_params
# Cache the original resources size to be used for pagination meta
@_jsonapi_original_size = resources.size
if resources.respond_to?(:offset)
resources = resources.offset(offset).limit(limit)
else
resources = resources[(offset)..(offset + limit - 1)] || []
end
block_given? ? yield(resources) : resources
end
# Generates the pagination links
#
# @return [Array]
def jsonapi_pagination(resources)
links = { self: request.base_url + CGI.unescape(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
# Generates pagination numbers
#
# @return [Hash] with the first, previous, next, current, last page numbers
def jsonapi_pagination_meta(resources)
return {} unless JSONAPI::Rails.is_collection?(resources)
_, limit, page = jsonapi_pagination_params
numbers = { current: page }
total = @_jsonapi_original_size
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
# Extracts the pagination params
#
# @return [Array] with the offset, limit and the current page number
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
# 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]
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
# Fallback to Rack's parsed query string when Rails is not available
#
# @return [Hash]
def jsonapi_path_parameters
return request.path_parameters if request.respond_to?(:path_parameters)
request.send(:parse_query, request.query_string, '&;')
end
end
end