Using will_paginate on a collection of records changes the paginated results count?

614 Views Asked by At

We have models Subscription and SubscriptionCart. A Subscription has_many SubscriptionCart.

We have and use a relation between the two models to get a Subscription's oldest cart where the plan_id changed to the current Subscription plan_id (in other words, the first cart that defined the current Subscription plan)

The Subscription relation goes as follows:

has_one     :first_version_with_current_plan, -> {
    joins(:subscription)
      .where(subscription_carts: { status: "processed" })
      .where("subscription_carts.plan_id = subscriptions.plan_id")
      .order("subscription_carts.authorized_at ASC")
  }, class_name: "SubscriptionCart", inverse_of: :subscription

The above relation will return a Subscription (parent) with the first cart (child) where the plan_id changed to whatever the Subscription plan_id is.

We are using that relation in an index view where we are using will_paginate to display the results.

controller:

  def index
    @subscriptions = current_account.subscriptions
      .includes(:first_version_with_current_plan)
      .order("subscription_carts.authorized_at ASC") # relation attribute
      .paginate(page: params[:page], per_page: 20)
      
  end

The issue we are having is that before the .paginate method @subscriptions.count will return 50 but applying .paginate to the collection renders less than 10 total results in the view.

I'm suspecting will_paginate makes a second query behind the scenes that is breaking the results count, but I'm not sure as I haven't found much online.

Is there any explanation to this or any known workaround?

1

There are 1 best solutions below

6
max On

Pagination should change the count - the whole point is to limit the amount of data fetch from the database by applying limits and offsets. When paginating the count is always equal to or smaller than the per_page setting - after all you're only fetching that many rows from the table.

If you want a count of the total number of records you need to either create a separate count query on the scope without pagination:

def index
  scope = current_account.subscriptions
    .includes(:first_version_with_current_plan)
    .order("subscription_carts.authorized_at ASC")
  @count = scope.count
  @subscriptions = scope.paginate(page: params[:page], per_page: 20)
end

If you want a count of the total number of records you need to either create a separate count query on the scope without pagination or use counter caches on your model.