2011-07-13 10 views
8

tengo una consulta como esta:¿Por qué una consulta en carriles con un límite no funciona a menos .all se pone en el extremo

locations = Location.order('id ASC').limit(10) 

que devuelve un conjunto de registros de más o menos 500 - todos los registros de la tabla, es decir, la cláusula de límite se está ignorando.

Sin embargo, si pongo un .all en el extremo:

locations = Location.order('id ASC').limit(10).all 

funciona y devuelve 10 registros.

Este código se ejecuta en una tarea de rastrillo y estoy usando PostgreSQL si hay alguna diferencia.

¿Por qué se hace? Seguramente el .all no debería ser requerido. ¿Qué me estoy perdiendo?

+0

Me pregunto si es o no está vinculada a la carga diferida: consultas no se activan a menos .all, .First ... se adjunta – apneadiving

+0

¿Qué versión de Rails ¿Estas usando? Porque estoy usando 3.0.9 y no puedo reproducir esto ... – Gerry

+0

¿Qué versión de Rails está ejecutando? Funciona para mí en Rails 3.0x. ¿Has intentado anexar ".to_sql" al final para ver qué consulta está ejecutando? – samullen

Respuesta

5

creo que el comportamiento depende de cómo se está manejando la variable locations después de configurarla. Esto se debe a que Location.order('id ASC').limit(10) no está consultando registros pero está devolviendo un objeto del tipo ActiveRecord::Relation. La consulta sólo se producirá una vez que se llama a all, first, each, map, etc en ese objeto.

En mis pruebas,

Location.order('id ASC').limit(10).map { |l| l.id } 

devuelve una matriz de identificadores de 10 como era de esperar. Pero

Location.order('id ASC').limit(10).count 

devuelve el número total de localizaciones en la base de datos, ya que ejecuta el SQL

SELECT COUNT(*) FROM "locations" LIMIT 10 

que devuelve el recuento total de filas de localización (el límite está en el número de filas devueltas, no el conteo mismo).

Así que si está tratando el resultado de Location.order('id ASC').limit(10) como una matriz al recorrerlo, debería obtener el mismo resultado que si hubiera agregado all. Si llama al count, no lo hará. Es un poco desafortunado, ya que creo que idealmente deberían comportarse igual y no debería tener que saber que está tratando con un ActiveRecord::Relation en lugar de una matriz.

+0

OK, así que creo que lo has clavado. Estaba comprobando el tamaño de las ubicaciones usando coloca "# {locations.size} elementos para buscar" olvidando que las ubicaciones son una Relación en ese punto, no una matriz. Parece que .size tiene un comportamiento diferente en una relación y la matriz producida por una consulta en esa relación que ciertamente no es útil. –

1

autorización aquí es mi explicación primer lugar si lo hace Location.order('id ASC').limit(10).class verá en la próxima ActiveRecord::Relationsite with rails APIActiveRecord::Relation no tiene un método all sin embargo, incluye ActiveRecord::FinderMethods y si se mira allí que se encuentra pegado

# File activerecord/lib/active_record/relation/finder_methods.rb, line 142 
def all(*args) 
    args.any? ? apply_finder_options(args.first).to_a : to_a 
end 

por lo que las llamadas to_a método como se mencionó en la railscasts este método se define como

def to_a 
    ... 
    @records = eager_loading? ? find_with_associations : @klass.find_by_sql(arel.to_sql) 
    ... 
    @records 
end 

por lo que la consulta SQL en una tercera línea con @records = eager_loading? ? find_with_associations : @klass.find_by_sql(arel.to_sql)

Cuestiones relacionadas