Skip to content

Controller helper method for easier pagination #2

@nicolas-fricke

Description

@nicolas-fricke

Right now, to use the pagination in a Rails project, we have to write something like this in the controller:

def index
  @posts = Post.all
  paginated_posts = 
    RailsCursorPagination::Paginator
      .new(first: params[:first],
           before: params[:before],
           last: params[:last],
           after: params[:after])
      .fetch(with_total: params[:return_total])

  render json: paginated_posts
end

And this is without even supporting custom ordering. This is quite cumbersome, can lead to a lot of duplicated code, and therefore is also a source of potential bugs.

What we did in our project is to then add a helper method to our ApplicationController like so:

class ApplicationController < ActionController::API
  [...]

  private

  # Convenience method to paginate records with the RailsCursorPagination
  # gem and passing in the right parameter values.
  #
  # @param [ActiveRecord::Relation] records
  # @return [Hash]
  def paginate(records)
    RailsCursorPagination::Paginator
      .new(records,
           first: params[:first]&.to_i,
           after: params[:after],
           last: params[:last]&.to_i,
           before: params[:before])
      .fetch(with_total: ActiveModel::Type::Boolean.new.cast(params[:return_total]))
  end
end

this then allows our controllers to be as simple as

def index
  @posts = Post.all
  render json: paginate(@posts)
end

It would be great if such a method would be directly provided by the gem so that any client can make use of it. It could e.g. be part of a concern that a user can load into their controllers or directly include in their ApplicationController to have it available on all controllers.

We would also have to consider how to allow users to add ordering to this. But this should probably be an opt-in and maybe only allowing ordering on selected columns to avoid performance issues from API users that order on un-optimized columns. I could imagine an interface similar to:

paginate(@posts, allow_ordering: true, restrict_order_to: %i[id author])

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions