Skip to content

Instantly share code, notes, and snippets.

@dux
Last active January 6, 2023 18:21
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dux/b386e7efd6feac50cb9ac140ceac916e to your computer and use it in GitHub Desktop.
Save dux/b386e7efd6feac50cb9ac140ceac916e to your computer and use it in GitHub Desktop.
Trivial and fast (does not execute count or any other unneeded requests) Ruby / Rails / Sinatra / Lux pagination
# @list = Paginate.set User, size: 40, name: :upage
# Paginate.render @list
# using: https://github.com/dux/html-tag/
module Paginate
extend self
def set rset, opts={}
opts[:size] ||= 20
opts[:name] ||= :page
opts[opts[:name]] ||= Current.request.params[opts[:name]] || 1
size = opts[:size].to_i
page = opts[opts[:name]].to_i
# minimal recordset size is 5
size = 5 if size < 5
# default page is 1
page = 1 if page < 1
# get scope in array form with +1 record to see if we have a next one
data = rset
.offset((page - 1) * size)
.limit(size + 1)
.to_a
# do we have a next page?
has_next =
if data.length > size
data.pop
true
else
false
end
# inject variables in data array
data.define_singleton_method(:paginate_page) { page }
data.define_singleton_method(:paginate_size) { size }
data.define_singleton_method(:paginate_next) { has_next }
data.define_singleton_method(:paginate_name) { opts[:name] }
data
end
def render rset
return unless rset.respond_to?(:paginate_size)
return nil if rset.paginate_page == 1 && !rset.paginate_next
HtmlTagBuilder.div(class: :paginate) do |n|
n.div do |n|
if rset.paginate_page > 1
url = Url.current
rset.paginate_page == 1 ? url.delete(rset.paginate_name) : url.qs(rset.paginate_name, rset.paginate_page-1)
n.a(href: url.relative) { '&larr;' }
else
n.span { '&larr;' }
end
n.i rset.paginate_page == 1 ? '&bull;' : rset.paginate_page
if rset.paginate_next
url = Url.current
url.qs(rset.paginate_name, rset.paginate_page+1)
n.a(href: url.relative) { '&rarr;' }
else
n.span { '&rarr;' }
end
end
end
end
end
.paginate {
clear: both;
padding: 40px 0;
text-align:center;
div {
border:1px solid #ddd;
display:inline-block;
border-radius:4px;
margin:0 auto;
background-color: #fff;
i, span, a {
display:inline-block;
width:40px;
padding:10px;
text-align:center;
text-decoration:none;
color:#aaa;
}
i {
border-left:1px solid #eee;
border-right:1px solid #eee;
}
a {
color:#444;
&:hover { background-color: #f7f7f7; }
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment