Skip to content

Instantly share code, notes, and snippets.

@xiaohui-zhangxh
Last active January 6, 2024 11:20
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 xiaohui-zhangxh/fd07e37e5b7552fcd18a7e2c9b8a464e to your computer and use it in GitHub Desktop.
Save xiaohui-zhangxh/fd07e37e5b7552fcd18a7e2c9b8a464e to your computer and use it in GitHub Desktop.
Make active_model_serializers render Pagy result as jsonapi response, with pagination meta and links
class Api::ApplicationController < ActionController::API
include Pagy::Backend
include PagyCollectionSerializer::ControllerMixin
end
class Api::V1::DepartmentsController < Api::ApplicationController
def index
render json: pagy(Current.organization.departments)
end
end
require 'securerandom'
class PagyCollectionSerializer < ActiveModel::Serializer::CollectionSerializer
module ControllerMixin
def pagy_get_vars(collection, vars)
super.tap do |result|
result[:page] = params.dig(:page, :number)
result[:items] = params.dig(:page, :size).to_i
result[:items] = 10 if result[:items] <= 0
result[:items] = 100 if result[:items] > 100
end
end
%i[_render_option_json _render_with_renderer_json].each do |renderer_method|
define_method renderer_method do |resource, options|
if resource.is_a?(Array) && resource.length == 2 && resource[0].is_a?(Pagy)
options[:serializer] ||= PagyCollectionSerializer
pagy = resource[0]
unless options.key?(:meta)
options[:meta] = {
total_count: pagy.count,
current_page: pagy.page,
page_size: pagy.items,
prev_page: pagy.prev,
next_page: pagy.next
}
options[:meta].merge! options.delete(:merge_meta) if options.key?(:merge_meta)
end
end
super(resource, options)
end
end
end
module ModelMixin
METHOD_NAME = "pagy_from_pagy_collection_serializer".freeze
def self.mount(pagy, collection)
return if collection.instance_variable_defined?("@#{METHOD_NAME}")
collection.instance_variable_set("@#{METHOD_NAME}", pagy)
collection.define_singleton_method(METHOD_NAME) { instance_variable_get("@#{METHOD_NAME}") }
collection.extend(self)
end
def current_page
pagy_from_pagy_collection_serializer.page
end
def total_pages
pagy_from_pagy_collection_serializer.pages
end
def next_page
pagy_from_pagy_collection_serializer.next
end
def per_page
pagy_from_pagy_collection_serializer.items
end
end
def initialize(pagy_result, options = {})
pagy, collection = pagy_result
ModelMixin.mount(pagy, collection)
super(collection, options)
end
def paginated?
true
end
end
{
"data": [
{
"id": "14",
"type": "departments",
"attributes": {
"name": "t5",
"created_at": "2023-12-31T18:15:26.614+08:00",
"updated_at": "2023-12-31T18:15:26.614+08:00",
"parent_id": 10,
"employees_count": 0
}
},
{
"id": "15",
"type": "departments",
"attributes": {
"name": "t5",
"created_at": "2023-12-31T18:15:48.624+08:00",
"updated_at": "2023-12-31T18:15:48.624+08:00",
"parent_id": 11,
"employees_count": 0
}
},
{
"id": "16",
"type": "departments",
"attributes": {
"name": "t15",
"created_at": "2023-12-31T18:15:54.594+08:00",
"updated_at": "2023-12-31T18:15:54.594+08:00",
"parent_id": 11,
"employees_count": 0
}
}
],
"links": {
"self": "http://open.lvh.me:3000/api/v1/departments?page%5Bnumber%5D=2&page%5Bsize%5D=5",
"first": "http://open.lvh.me:3000/api/v1/departments?page%5Bnumber%5D=1&page%5Bsize%5D=5",
"prev": "http://open.lvh.me:3000/api/v1/departments?page%5Bnumber%5D=1&page%5Bsize%5D=5",
"next": null,
"last": "http://open.lvh.me:3000/api/v1/departments?page%5Bnumber%5D=2&page%5Bsize%5D=5"
},
"meta": {
"total_count": 8,
"current_page": 2,
"page_size": 5,
"prev_page": 1,
"next_page": null
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment