Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Paginating a shuffled ActiveRecord query

I am attempting to paginate a shuffled ActiveRecord query. The syntax for doing this using the Kaminari gem is:

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

The issue with this is that User.all is re-shuffled on each pagination request, causing duplicate records to be called. Is there any way to prevent this kind of duplication?

like image 213
neon Avatar asked Apr 01 '12 18:04

neon


2 Answers

You need to pass seed for rand between queries

params[:seed] ||= Random.new_seed
srand params[:seed].to_i
@users = Kaminari.paginate_array(User.all.shuffle).page(params[:page]).per(20)

And in view add params[:seed] to all kaminari links to pages

like image 130
mikdiet Avatar answered Sep 30 '22 03:09

mikdiet


As KandadaBoggu points out above, retrieving all of the User records from the database is inefficient when you only need 20. I would suggest using MySQL's RAND() function to perform the randomization before you return from the database. You can still pass a seed value to RAND() to make sure the shuffling only happens once per session.

For example:

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

I don't have a MySQL installation to test against, but this should perform better than your original code.

like image 21
Brandan Avatar answered Sep 30 '22 02:09

Brandan