シャッフルされたActiveRecordクエリをページ分割しようとしています。カミナリジェムを使用してこれを行うための構文は次のとおりです。
@users = Kaminari.paginate_array(User.all.shuffle).page(params[:page]).per(20)
これに伴う問題は、User.all
ページネーション要求ごとに再シャッフルされ、重複するレコードが呼び出されることです。この種の重複を防ぐ方法はありますか?
シャッフルされたActiveRecordクエリをページ分割しようとしています。カミナリジェムを使用してこれを行うための構文は次のとおりです。
@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()
関数を使用してランダム化を実行することをお勧めします。シード値を渡して、シャッフルがセッションごとに 1 回だけ行われるようにすることもできます。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
データがそれほど大きくない場合、おそらく同じ結果が生成されるためです。