Search code examples
ruby-on-railsserializationpaginationactive-model-serializers

Rails active_model_serializer with pagination


I'm using active_model_serializer. Now I want to serialize an object with pagination, should I do the pagination logic in the controller or in the serializer?

If I choose to do the pagination in serializer, I need to pass the page_number and per_page to the serializer. How should I do that? My understanding is serializer only takes the model object.


Solution

  • Single Use Solution

    Regular serializers are only concerned with single items - not paginated lists. The most straight forward way to add pagination is in the controller:

    customers = Customer.page(params[:page])
    respond_with customers, meta: {
      current_page: customers.current_page,
      next_page: customers.next_page,
      prev_page: customers.prev_page,
      total_pages: customers.total_pages,
      total_count: customers.total_count
    }
    

    Reusable Solution

    However, this is pretty tedious if you need pagination logic for multiple objects. Looking through the documentation for active_model_serializers you'll come across an ArraySerializer for serializing an array of objects. What I did was create pagination_serializer.rb using ArraySerializer to automatically add the meta tag for paginated arrays:

    # my_app/app/serializers/pagination_serializer.rb
    class PaginationSerializer < ActiveModel::Serializer::ArraySerializer
      def initialize(object, options={})
        meta_key = options[:meta_key] || :meta
        options[meta_key] ||= {}
        options[meta_key][:pagination] = {
          current_page: object.current_page,
          next_page: object.next_page,
          prev_page: object.prev_page,
          total_pages: object.total_pages,
          total_count: object.total_count
        }
        super(object, options)
      end
    end
    

    Once you have PaginationSerializer added to your rails app, you simple need to call it when you need pagination meta tags from your controller:

    customers = Customer.page(params[:page])
    respond_with customers, serializer: PaginationSerializer
    

    Note: I wrote this to use Kaminari as the paginator. However, it can easily be modified to work with any pagination gem or custom solution.