Skip to content

Instantly share code, notes, and snippets.

@ThisIsMissEm
Last active August 29, 2015 14:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ThisIsMissEm/d3052188d6de319ffa21 to your computer and use it in GitHub Desktop.
Save ThisIsMissEm/d3052188d6de319ffa21 to your computer and use it in GitHub Desktop.
So, I hacked together something for Grape to give me opaque cursors for pagination with Kaminari. It works, but could be a lot nicer. For instance, it doesn't handle query parameters at the moment.
require 'msgpack'
require "kaminari/grape"
module API
module V1
module Pagination
def self.included(base)
base.class_eval do
helpers do
def paginate(collection)
options = {
page: 0,
per_page: ::Kaminari.config.default_per_page || 100,
}
if params.has_key?(:cursor)
cursor = API::V1::Pagination.decode_cursor(params[:cursor])
options.merge!(cursor)
end
collection.page(options[:page]).per(options[:per_page]).tap do |data|
header "next_cursor", API::V1::Pagination.encode_cursor(page: data.next_page, per_page: options[:per_page]) unless data.last_page?
header "prev_cursor", API::V1::Pagination.encode_cursor(page: data.prev_page, per_page: options[:per_page]) unless data.first_page?
end
end
end
def self.paginate(options = {})
params do
optional :cursor, type: String, desc: 'Cursor for paging results.'
end
end
end
end
class << self
def decode_cursor(cursor)
data = Base64.urlsafe_decode64(cursor + '=' * (offset = 4 - cursor.size.modulo(4) and offset == 4 ? 0 : offset))
data = MessagePack.unpack(data, symbolize_keys: true)
data
end
def encode_cursor(options)
cursor = MessagePack.pack(options)
cursor = Base64.urlsafe_encode64(cursor).gsub('=', '')
cursor
end
end
end
end
end
@ThisIsMissEm
Copy link
Author

Oh, yeah, using JSON here really isn't right, nor is using Base64 and then removing the padding nice either. However, on Base64, what I really wanted was Base62, but all the Base62 gems do nasty shit like monkey-patching things.

It'd probably be better to use MSGPack or something, maybe.

@justinsoong
Copy link

i want to implement cursor based pagination, how would i drop in this class, and use it? @miksago

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment