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
|
# File 'lib/clean_pagination.rb', line 3
def paginate total_items, max_range_size, options = {}
options[:allow_render] = true if options[:allow_render].nil?
options[:raise_errors] ||= false
['Accept-Ranges'] = 'items'
['Range-Unit'] = 'items'
requested_from, requested_to = 0, [0, total_items - 1].max
if request.['Range-Unit'] == 'items' &&
request.['Range'].present?
if request.['Range'] =~ /(\d+)-(\d*)/
requested_from, requested_to = $1.to_i, ($2.present? ? $2.to_i : Float::INFINITY)
end
end
if (requested_from > requested_to) ||
(requested_from > 0 && requested_from >= total_items)
response.status = 416
['Content-Range'] = "*/#{total_items}"
message = 'invalid pagination range'
raise RangeError, message if options[:raise_errors]
render text: message if options[:allow_render]
return
end
available_to = [requested_to,
total_items - 1,
requested_from + max_range_size - 1
].min
available_limit = available_to - requested_from + 1
if available_limit == 0
['Content-Range'] = "*/0"
else
['Content-Range'] = "#{
requested_from
}-#{
available_to
}/#{
total_items < Float::INFINITY ? total_items : '*'
}"
end
yield available_limit, requested_from
if available_limit < total_items && response.status == 200
response.status = 206
end
requested_limit = requested_to - requested_from + 1
links = []
if available_to < total_items - 1
links << "<#{request.url}>; rel=\"next\"; items=\"#{
available_to + 1
}-#{
suppress_infinity(available_to + requested_limit)
}\""
if total_items < Float::INFINITY
links << "<#{request.url}>; rel=\"last\"; items=\"#{
((total_items-1) / available_limit) * available_limit
}-#{
(((total_items-1) / available_limit) * available_limit) + requested_limit - 1
}\""
end
end
if requested_from > 0
previous_from = [0, requested_from - [requested_limit, max_range_size].min].max
links << "<#{request.url}>; rel=\"prev\"; items=\"#{
previous_from
}-#{
suppress_infinity(previous_from + requested_limit - 1)
}\""
links << "<#{request.url}>; rel=\"first\"; items=\"0-#{suppress_infinity(requested_limit-1)}\""
end
['Link'] = links.join ', ' unless links.empty?
end
|