Tengo una base de datos de películas con atributos. Me gustaría devolver un lote consultado de esas películas en orden aleatorio a una plantilla con paginación. Estoy usando will_paginate. Intenté lo siguiente:Rails 3, will_paginate, random, repeating records, Postgres, setseed failure
## MoviesController
movies = Movie.get_movies(query_string) # a method in Movie model that takes in
# a query_string and fetches movies
# with user-set params
@movies = movies.order('random()').page(params[:page]).per_page(16)
Esto funciona bien, excepto que las películas se repiten de página a página. Se han publicado soluciones a este problema here y here. Esos enlaces explican que, dado que random() semilla se restablece de página a página, no hay consistencia y OFFSET se vuelve inútil. Ofrecen excelentes soluciones para los usuarios de MySQL, ya que su función rand (n) toma una semilla n. Postgres, sin embargo, no hace esto. Usted tiene que declarar setSeed (n) enSELECT antes de emitir aleatorio() en ORDEN.
así que he intentado el camino postgres para establecer la semilla:
@movies = movies.select('setseed(.5)').order('random()').page(params[:page]).per_page(16)
Curiosamente, que devuelve objetos de película sin ningún tipo de atributos. El siguiente fue levantado de la plantilla:
ActiveModel :: MissingAttributeError en las películas de acción #
falta de atributos: some_movie_attribute
I depurado esto y, una vez que la pila alcanza action_controller/metal, @movies contenido:
[#<Movie >, #<Movie >, #<Movie >, #<Movie >, #<Movie >, #<Movie >, #<Movie >, #<Movie >, #<Movie >, #<Movie >, #<Movie >, #<Movie >, #<Movie >, #<Movie >, #<Movie >, #<Movie >]
Ese número de objetos de película (18) corresponde a la cantidad de películas devueltas de la consulta.
También probé el siguiente para ver si setSeed (n) era el problema eliminando el método de orden aleatorio:
@movies = movies.select('setseed(.5)').page(params[:page]).per_page(16)
Esto devuelve el mismo no de atributo objetos de película como layed anteriormente. Entonces parece que setseed (n) es realmente el problema.
he intentado un par de soluciones, como:
# MoviesController
movies = Movie.get_movies(query_string)
shuf_movs = movies.shuffle ## effectively turns shuf_movs into an array
@movies = shuf_movs.paginate(:page => params[:page], :per_page => 16)
Eso también volvió páginas con las películas que se repiten. Pensé que esto era porque la paginación necesitaba que los objetos se ordenaran por algo, y no se pueden establecer las semillas en Array # shuffle. Así que traté de escribir mi propio código de aleatorización que almacenaría temporalmente un id para que lo ordenaran en los objetos de la película. (Disculpe el código descuidado):
# Movie model
attr_accessor :rand_id
# MoviesController
movies = get_movies(query_string)
movies_count = movies.count
r = Random.new
nums = []
rand_movs = []
id = 1
while nums.count != movies_count
num = r.rand(0..movies_count - 1)
if !(nums.include?(num))
movie = movies[num]
movie.rand_id = id
rand_movs << movie
nums << num
id += 1
end
end
@movies = rand_movs.sort_by { |a| a.rand_id }.paginate(:page => params[:page], :per_page => 16)
Que todavía produjo películas repetidas en diferentes páginas.En este punto me doy cuenta de que will_paginate no acepta lo que ha ordenado antes de llamar al paginate. Así que probé esto:
@movies = rand_movs.paginate(:order => 'rand_id', :page => params[:page], :per_page => 16)
Que aún repite registros. : orden -> 'rand_id' se ignora porque : orden solo importa cuando se trata de objetos ActiveRecord, no de matrices.
Así que setseed (n) parece ser mi única esperanza para lograr registros aleatorios no repetitivos usando will_paginate. ¿Algunas ideas?
Gracias!
El SELECT especifica las columnas en la consulta, y no especificaste ninguno, solo la semilla. No estoy seguro si funcionará, pero intente esto: '.select ('*, setseed (1)')' – Matzi