我使用 Kaminari gem 进行分页。
尝试运行此类代码时出现异常:
Distributor.all.page(123123213213132113322)
=> ActiveRecord::StatementInvalid (Mysql2::Error: 你的 SQL 语法有错误;检查与你的 MySQL 对应的手册 服务器版本,以便在附近使用正确的语法 '3078080330328302833025' 在第 1 行:SELECT
.* FROMdistributors
限制 11 偏移 3078080330328302833025)distributors
我已经尝试将此类配置添加到初始化程序中,但没有帮助:
Kaminari.configure do |config|
config.max_pages = 1000000000
end
在
#page
方法调用上强制限制最大页数的正确方法是什么,或者是否有其他方法可以避免此类异常?
您可能会遇到未记录的 MySql 偏移量限制
3689348814741910324
— AKA 3_689_348_814_741_910_324
AKA 3,689,348,814,741,910,324
AKA ((2^65) / 10) + 1)
AKA ((2**65) / 10) + 1
。我是这样处理的。我确信这里会有一些有用的金块。 具体来说,您可以编写自己的分页助手来包装 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