分散洗牌的ActiveRecord查询

时间:2012-04-01 18:36:09

标签: mysql ruby-on-rails ruby-on-rails-3 pagination kaminari

我正在尝试对洗牌的ActiveRecord查询进行分页。使用Kaminari gem执行此操作的语法是:

@users = Kaminari.paginate_array(User.all.shuffle).page(params[:page]).per(20)

这个问题是User.all在每个分页请求上重新洗牌,导致重复记录被调用。有没有办法防止这种重复?

3 个答案:

答案 0 :(得分:5)

您需要在查询之间传递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链接

答案 1 :(得分:3)

正如KandadaBoggu指出的那样,当您只需要20时,从数据库中检索所有User记录效率很低。我建议使用MySQL's RAND() function来执行之前的随机化 >您从数据库返回。您仍然可以将种子值传递给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安装,但这应该比原始代码执行得更好。

答案 2 :(得分:0)

你也可以这样做:

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很可能会产生相同的结果。