2010-06-03 3 views
1

Je dois trouver tous les enregistrements d'une ressource particulière et les afficher dans un ordre aléatoire, mais avec une pagination cohérente (vous ne verrez pas le même enregistrement deux fois si vous lancez la pagination). L'ordre d'affichage doit être aléatoire chaque fois qu'un utilisateur visite une page. J'utilise will_paginate. Aucun conseil?Rails Enregistrement actif aléatoire avec pagination

Répondre

4

Stockez un nombre aléatoire dans les cookies de session utilisateur, puis utilisez cela comme germe pour votre fonction aléatoire de base de données. Ce sera le même jusqu'à ce que l'utilisateur ferme son navigateur, et donc ils vont tous voir des enregistrements aléatoires, cohérents:

Obtenir un grand nombre aléatoire:

cookies[:seed] = SecureRandom.random_number.to_s[2..20].to_i 

Utilisez cette graine par exemple MySQL:

SomeModel.all.order("RAND ?", cookies[:seed]) 
+0

Mise à jour: Je viens de réaliser une chose: vous devriez probablement faire de la graine aléatoire une partie de vos URLs, de sorte que lorsqu'un utilisateur stocke un signet ou enregistre une URL, il ne cassera pas la pagination. Vous pourriez alors faire des graines || = params [: seed] || session_seed – Houen

1

Si vous utilisez une base de données comme MySQL qui a une fonction de randomize tels que RAND(), vous pouvez simplement ajouter à votre requête de pagination comme ceci:

Resource.paginate(... :order => "RAND()" ...) 

Découvrez quelques-unes des commentaires ici concernant problèmes de performance: https://rails.lighthouseapp.com/projects/8994/tickets/1274-patch-add-support-for-order-random-in-queries

+0

Cela ne fonctionnera pas. Lors du changement de pages (c'est-à-dire 1 à 2), la requête est exécutée une deuxième fois, et il est possible d'avoir une entrée en double apparaissant (une entrée qui était sur la page 1 apparaissant également sur la page 2). –

+0

Je pensais que vous vouliez dire que vous vouliez simplement que les entrées de chaque page soient aléatoires. Vous pouvez stocker les pages précédemment vues dans un tableau de session et les filtrer sur la prochaine requête, mais cela semble vraiment hacky et cassant. –

+0

Oui, cela ne semble pas être une très bonne solution. Je suis juste un peu surpris que quelque chose de mieux n'existe pas. Je l'ai déjà vu implémenté dans des applications Ruby on Rails comme http://sortfolio.com/. –

2

Ceci n'est pas standard à ma connaissance. Je peux voir une utilisation pour cela par exemple pour les tests en ligne.

Je suggère d'utiliser une liste par session/utilisateur. Donc, quand un utilisateur va d'abord à la page, vous déterminez une liste d'ID, dans un ordre aléatoire, et toutes les vues consécutives vous utiliserez cette liste pour montrer l'ordre correct pour cet utilisateur/session. J'espère que la quantité de lignes est limitée, et cela aurait du sens, par exemple pour les tests. De plus, lorsqu'un utilisateur laisserait un test avant de le terminer complètement, il pourrait continuer là où il l'avait laissé. Mais peut-être que ce n'est pas pertinent pour vous.

Espérons que cela aide.

1

Vous ne savez pas si vous avez encore besoin d'aide pour cela. Une solution que j'ai faite dans le passé est de faire la requête avec RAND mais sans pagination au début. Ensuite, stockez ces ID d'enregistrement et utilisez cette liste stockée pour rechercher et paginer à partir de là. La requête RAND initiale peut être définie pour s'exécuter uniquement lorsque la page est 1 ou nulle. Juste une pensée.

+0

Merci pour l'idée.Je n'ai pas regardé cela depuis longtemps et je ne me souviens plus où il était utilisé! J'apprécie la réponse cependant. –

0

j'ai fini-avec cette solution qui a fonctionné pour moi sur Postgres:

session[:seed] ||= rand() # should be between [-1..1] 
seed = session[:seed] 
Product.select("setseed(#{seed})").first 
Product.order('random()').limit(10).offset(params[:offset]) 
Questions connexes