Techioz Blog

group by と Rails を使用した複雑なページネーションのシナリオ

概要

おそらく 9000 行以上のテーブルがあり、(Kaminari を使用して) ページネーションを行おうとしていますが、その方法を理解するのに問題があります。

私のシナリオでは、私は e コマース ストアを持っており、顧客は注文の資金を PayPal に転送するようリクエストできます。

私のモデルは次のとおりです。

# customer.rb

has_many :transfers, through: :orders
# order.rb

belongs_to :customer
has_one :transfer
# transfer.rb

belongs_to :order
belongs_to :customer

すべての転送をページ分割しようとしていますが、顧客ごとにグループ化されています。現在、次のようにしてこれを行うことができます。

# transfers_controller.rb

@transfers = Transfer.includes(:order, :customer)

そして、私のビューで次のようにループします。

# index.html.erb

@transfers.group_by(&:customer).each

これはうまく機能しており、顧客ごとにグループ化された転送をループできます。つまり、大量の結果を表示するためにページ分割が必要になるという問題に遭遇するまでは。

もちろん、次のように Kaminari を使って簡単にページネーションすることもできます。

@transfers = Transfer.includes(:order, :customer).page(params[:page])

これの問題は、これが私の group_by とちょっと違うことです。顧客をループしている可能性があり、ページごとの制限に達したためにすべての転送が含まれていない可能性がありますが、これは誤解を招きます。私の考えでは、顧客ごとにグループ化するときに、少なくともその顧客のすべての転送が表示されていることを確認する必要があります。

Kaminari には配列のページネーション メソッドもあることはわかっているので、次のようにすることができます。

@paginatable_array = Kaminari.paginate_array(@transfers.group_by(&:customer)).page(params[:page]).per(10)

そして私の見解では:

# index.html.erb

@paginatable_array.each

しかし、この方向の問題は、最初にすべての行をクエリする必要があるため、最終的にはクエリ全体を 9000 以上の行に対して実行する必要があるため、ページネーションがまったく役に立たないことです。

このシナリオでこのクエリ/ページを最適化できるようにページ分割する方法について何かヘルプはありますか?

アップデート:

なぜこれを思いつかなかったのかわかりませんが、脳屁ですか?ただし、コントローラーで行うように、代わりに Customer によってクエリを実行するのが最も簡単でした。

@customers = Customer.includes(:orders, :transfers).page(params[:page])

そして私の見解では:

@customers.each do |customer|
  customer.transfers.each do |transfer|
    # do stuff
  end
end

このようにして、ページネーションするときに、顧客に基づいてページネーションすることになります。

解決策

投稿の更新を通じて元の質問に回答しましたが、ここにも投稿します:

なぜこれを思いつかなかったのかわかりませんが、脳屁ですか?ただし、コントローラーで行うように、代わりに Customer によってクエリを実行するのが最も簡単でした。

@customers = Customer.includes(:orders, :transfers).page(params[:page])

そして私の見解では:

@customers.each do |customer|
  customer.transfers.each do |transfer|
    # do stuff
  end
end

こうすることで、ページネーションするときに顧客に対してページネーションを行うことになり、ループ中にページネーションによって顧客の転送が中断される可能性がなくなります。