2012-04-01 13 views
5

Sto tentando di impaginare una query di ActiveRecord mescolata. La sintassi per fare questo usando la gemma Kaminari è:Impaginazione di una query di ActiveRecord mescolata

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

Il problema con questo è che User.all è rimescolati su ogni richiesta di impaginazione, causando record duplicati da chiamare. C'è un modo per prevenire questo tipo di duplicazione?

+1

La chiamata di 'User.all' può causare un rallentamento significativo del server. Anche se hai solo 100 di utenti pagherai il costo non necessario di portare tutti gli utenti nello spazio di memoria rubino in ogni richiesta. –

risposta

5

è necessario passare seme per rand tra le query

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

E in vista aggiungere params [: semi] per tutti i link Kaminari alle pagine

+0

grazie per il piombo! se possibile, potresti spiegare come funziona? Non sto seguendo completamente, ancora incerto su come implementare questa risposta. – neon

+0

Puoi leggere i documenti API come funziona seed http://ruby-doc.org/core-1.9.2/Random.html – MikDiet

+0

L'ho capito, ma ora l'array viene visualizzato nello stesso ordine mescolato in modo coerente - vale a dire anche dopo l'utente si disconnette e torna indietro, l'array rimane nello stesso ordine inizialmente mescolato anziché essere rimischiato. Strano. – neon

3

Come KandadaBoggu sottolinea sopra, recuperando tutti i User i record dal database sono inefficienti quando ne hai solo bisogno 20. Suggerirei di utilizzare MySQL's RAND() function per eseguire la randomizzazione prima del che si ritorna dal database. È ancora possibile passare un valore seme a RAND() per assicurarsi che lo shuffling avvenga solo una volta per sessione.

Ad esempio:

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 

Non ho un'installazione di MySQL per testare contro, ma questo dovrebbe funzionare meglio di quanto il tuo codice originale.

0

Si può anche fare questo:

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 

Perché Random.new_seed genererà molto probabilmente lo stesso risultato se i dati non è così grande.

Problemi correlati