2011-02-13 14 views
14

Tengo un problema extraño en una implementación de Heroku que parece que no puedo duplicar localmente. Básicamente, cuando encuentro todo en un modelo específico en lugar de ordenar por ID, parece devolverlos en ningún orden.ActiveRecord Find All no ordena por ID?

Normalmente los registros salen de este modo:

>> Model.all 

=> [<model id: 2>,<model id: 1>,<model id: 3>,<model id: 4>,<model id: 5>] 

... y así sucesivamente.

Si llamo explícitamente al Model.order("id ASC"), devuelve los modelos como se esperaba.

¿Qué ofrece? ¿Por qué encontraría que todos no devuelven los objetos en orden de ID descendente?

Respuesta

23

El pedido por ID es no garantizado de forma predeterminada, ya que depende de la base de datos cómo se ordena una consulta no ordenada (generalmente no está especificada). Puede que sea siempre ser ordenada por la definición de un default scope en la parte superior de su modelo de este modo:

default_scope { order('id ASC') } 

Entonces llamando Model.all será equivalente a llamar Model.order('id ASC').

+0

esto va a cambiar todas sus consultas, puse una manera de hacer un par de métodos adicionales como una extensión [aquí] (http://stackoverflow.com/a/22906452/1802527) para estar disponible en todos los modelos – Alexis

+0

Primero, ¿debería ser 'default_scope {order id:: asc}' en las nuevas versiones de Rails? Además, ¿es esto susceptible a los problemas de inicialización del modelo con 'default_scope'? – BalinKingOfMoria

+0

@BalinKingOfMoria Sí, lo he actualizado. ¿Qué modelo de problemas de inicialización? –

7

En SQL, tablas se consideran conjuntos de registros, no listas de los registros, y una consulta 'select' no está garantizada para devolver registros en un orden particular a menos que una "orden por cláusula es específicamente incluido. Puede ver que los resultados vuelven en un orden particular a veces, pero eso no significa que pueda o deba suponer que siempre será así.

Al utilizar ActiveRecord, puede forzar una cláusula predeterminada de 'ordenar por' si lo desea al especificar un alcance predeterminado. En general, eso es una mala idea, porque forzará al servidor a hacer más trabajo para darle un conjunto de resultados ordenados, incluso cuando no lo necesite ordenado. Además, la clasificación en el campo 'id' suele ser inapropiada, ya que el punto de 'id' debe ser un identificador de registro opaco sin otro propósito o significado que el de ser único para un registro dado en una tabla.

0

Ok, para el registro, mis pruebas arrojaron la siguiente explicación: en PostgreSQL (y posiblemente en otros) el método "todos" aparece en devuelve las cosas en el orden de su último guardado (ver comentario más abajo). Por lo tanto, el elemento guardado más reciente devuelve el último y el ítem guardado más antiguo regresa primero. Pude "arreglar" el pedido volviendo a guardar todos los modelos en orden de ID.

Este problema no existe en SQLite, etc., pero la respuesta de Steve tiene sentido (no hay garantía de que los registros vuelvan en un orden específico). Además, la respuesta de Andrew Marshall sí funciona.

+3

No, realmente no devuelve las cosas en el orden de su último guardado. Lo que estás viendo es una coincidencia. Cuando el optimizador de consultas en dbms elige un plan de ejecución diferente, las filas volverán en un orden diferente. (A menos que exista un ORDER BY explícito.) Y hay muchas razones para elegir un plan diferente, siendo el más común un cambio en el número de filas en una tabla. –

2

Solo una actualización de la gran respuesta de Andrew (lo siento, no tengo la reputación suficiente para agregarla como comentario), ahora se eliminó la compatibilidad para llamar a #default_scope sin un bloque. Actualmente la sintaxis es aceptable en Modelo:

default_scope { sort(id: 'ASC') } 
Cuestiones relacionadas