Techioz Blog

レール |カミナリ: 最大ページ数を制限するにはどうすればよいですか?

概要

ページネーションには Kaminari gem を使用しています。

このようなコードを実行しようとすると例外が発生します。

Distributor.all.page(123123213213132113322)

すでにそのような構成をイニシャライザに追加しようとしましたが、役に立ちません:

Kaminari.configure do |config|
  config.max_pages = 1000000000
end

#page メソッド呼び出しで最大ページを強制的に制限する正しい方法は何ですか、それともそのような例外を回避するための他の方法はありますか?

解決策

おそらく文書化されていない MySql オフセット制限 3689348814741910324 — 別名 3_689_348_814_741_910_324 別名 3,689,348,814,741,910,324 別名 ((2^65) / 10) + 1) 別名 ((2**65) /10)+1。 Graffiti バックエンド API を作成しているときに、同じことに遭遇しました。

これが私がそれに対処した方法です。ここにはきっと役に立つナゲットがあるでしょう。 具体的には、以下で行ったように、いくつかのフィルタリングを適用する Kaminari ページ呼び出しをラップする独自のページネーション ヘルパーを作成できます。 (発生したエラーをレスキュー/キャッチし、情報メッセージとしてユーザーに送り返します。)

class ApplicationResource < Graphiti::Resource

  ###################################################################
  #
  # Constants
  #
  ###################################################################

  # Exceeding this integer value in a query causes MySQL to overflow the integer, typically raising an error.
  # I found very little information about this limit online. I discovered it using trial and error, otherwise I'd
  # explain more.
  MYSQL_QUERY_INT_MAX = 3_689_348_814_741_910_324 # ((2**65) / 10) + 1

  CURRENT_PAGE_DEFAULT = 1 # Graphiti takes care of this behavior itself internally. This constant is for reference only.
  CURRENT_PAGE_MIN     = 1
  CURRENT_PAGE_MAX     = MYSQL_QUERY_INT_MAX

  RESULTS_PER_PAGE_DEFAULT = 20
  RESULTS_PER_PAGE_MIN     = 1
  RESULTS_PER_PAGE_MAX     = 250



  ###################################################################
  #
  # Pagination
  #
  # The `scope` draws from and builds upon the `base_scope` provided by the child resource.
  # The `current_page` and `results_per_page` come from the request
  # params in the format: /resources?page[number]=2&page[size]=10
  #
  ###################################################################
  self.default_page_size = RESULTS_PER_PAGE_DEFAULT # Override default from Graphiti::Resource which is 10.
  self.max_page_size     = RESULTS_PER_PAGE_MAX     # Override default from Graphiti::Resource which is 1,000.

  paginate do |scope, current_page, results_per_page|

    # Apply defaults if the respective parameters are omitted.
    # No need to check current_page as Graphiti internally enforces a default value (1).
    results_per_page = RESULTS_PER_PAGE_DEFAULT if results_per_page.nil?

    # Guard against invalid parameters.
    # No need to guard against RESULTS_PER_PAGE_MAX as Graphiti does that on its own via the max_page_size setting above.
    if results_per_page < RESULTS_PER_PAGE_MIN
      raise(Api::UnsupportedPageSizeMin.new(results_per_page, RESULTS_PER_PAGE_MIN))
    end
    if current_page < CURRENT_PAGE_MIN || current_page > CURRENT_PAGE_MAX
      raise(Api::InvalidPageNumber.new(current_page, CURRENT_PAGE_MIN, CURRENT_PAGE_MAX))
    end

    # Perform pagination (makes use of the kaminari gem).
    scope.page(current_page).per(results_per_page)
  end