我正在尝试对打乱的 ActiveRecord 查询进行分页。使用 Kaminari gem 执行此操作的语法是:
@users = Kaminari.paginate_array(User.all.shuffle).page(params[:page]).per(20)
这个问题是User.all
在每个分页请求上重新洗牌,导致重复记录被调用。有没有办法防止这种重复?
我正在尝试对打乱的 ActiveRecord 查询进行分页。使用 Kaminari gem 执行此操作的语法是:
@users = Kaminari.paginate_array(User.all.shuffle).page(params[:page]).per(20)
这个问题是User.all
在每个分页请求上重新洗牌,导致重复记录被调用。有没有办法防止这种重复?
您需要在查询之间为 rand 传递种子
params[:seed] ||= Random.new_seed
srand params[:seed].to_i
@users = Kaminari.paginate_array(User.all.shuffle).page(params[:page]).per(20)
并在视图中将 params[:seed] 添加到所有页面的 kaminari 链接
正如上面 KandadaBoggu 所指出的,User
当您只需要 20 条记录时,从数据库中检索所有记录是低效的。我建议您在从数据库返回之前使用MySQL 的RAND()
函数来执行随机化。您仍然可以将种子值传递给以确保每个会话只发生一次洗牌。RAND()
例如:
class User < ActiveRecord::Base
def self.randomized(seed = nil)
seed = seed.to_i rescue 0
order("RAND(#{seed})")
end
end
class UsersController < ApplicationController
before_filter :set_random_seed
def index
@users = User.randomized(session[:seed]).page(params[:page]).per(20)
end
private
def set_random_seed
session[:seed] ||= Random.new_seed
end
end
我没有要测试的 MySQL 安装,但这应该比您的原始代码执行得更好。
你也可以这样做:
class UsersController < ApplicationController
USERS_SEED = 1000 # Or any another not-so-big number
def set_random_seed
session[:seed] ||= Random.rand(USERS_SEED)
end
end
因为Random.new_seed
如果您的数据不是那么大,很可能会产生相同的结果。