2012-05-25 12 views
52

Soy un desarrollador de PHP aprendiendo la imponencia de Ruby on Rails, me encanta ActiveRecord y noté algo realmente interesante, que es cómo los métodos ActiveRecord detectan el final de la cadena de métodos para ejecutar la consulta.¿Cómo encadena Rails ActiveRecord las cláusulas "where" sin múltiples consultas?

@person = Person.where(name: 'Jason').where(age: 26) 

# In my humble imagination I'd think that each where() executes a database query 
# But in reality, it doesn't until the last method in the chain 

¿Cómo funciona esta hechicería?

+0

no lo hace en el último método. No tiene forma de saber eso. Considere 'x = Person.where (..); @person = x.where (..) ', que debería funcionar de forma idéntica. Lo hace en algún momento más tarde, entonces, ¿cuál es el desencadenante? ;-) –

Respuesta

122

El método where devuelve un objeto ActiveRecord::Relation y, por sí solo, este objeto no emite una consulta de base de datos. Es donde utiliza este objeto que importa.

En la consola, es probable que estés haciendo esto:

@person = Person.where(name: "Jason") 

Y luego blammo se emite una consulta de base de datos y devuelve lo que parece ser una serie de todo el mundo llamado Jason. Yay, Active Record!

Pero entonces se hace algo como esto:

@person = Person.where(name: "Jason").where(age: 26) 

Y luego que emite otra consulta, pero esto es para las personas que son llamados Jason, que son 26. Pero es sólo la emisión de uno consulta, por lo que cuando ¿La otra consulta ir?


Como otros han sugerido, esto está sucediendo porque el método where devuelve un objeto proxy. En realidad, no realiza una consulta y devuelve un conjunto de datos a menos que se le pida que haga eso.

Cuando ejecuta cualquier cosa en la consola, se imprimirá la versión inspeccionada del resultado de lo que sea que haya ejecutado. Si coloca 1 en la consola y pulsa enter, obtendrá 1 porque 1.inspect es 1. ¡Magia! Lo mismo vale para "1". Una variedad de otros objetos no tienen un método inspect definido y, por lo tanto, Ruby vuelve al que está en Object, que devuelve algo espantoso como <Object#23adbf42560>.

Cada objeto ActiveRecord::Relation único tiene el método inspect definido en él para que se produzca una consulta. Cuando escribe la consulta en su consola, IRB llamará al inspect en el valor de retorno de esa consulta y obtendrá algo casi legible, como la matriz que verá.


Si se acaba de emitir esta en una secuencia de comandos estándar de Ruby, entonces no hay ninguna consulta se ejecutaría hasta que el objeto fue inspeccionado (a través de inspect) o fue reiterado mediante el uso de each, o tenían el método to_a invocado.

Hasta una de esas tres cosas sucede, se pueden encadenar tantas where declaraciones sobre como le va a gustar y luego, cuando hacer llamada inspect, to_a o each en él, entonces será finalmente ejecutar esa consulta.

+1

¡Entretenido e informativo! ¡Gracias! – henrebotha

+1

Relevante [Railscast] (http://railscasts.com/episodes/239-activerecord-relation-walkthrough) explicándolo con el código fuente de Rails. – flexus

+0

mente impresionado ...... – sixty4bit

4

Puede leer el código, pero un concepto aquí es el patrón de proxy.

Probablemente @person no es el objeto real sino un proxy para este objeto y cuando se necesita algún atributo, el registro activo finalmente ejecuta la consulta. Hibernate tiene el mismo concepto.

6

Hay una serie de métodos que se conocen como "pateadores" que realmente disparan la consulta a la base de datos. Antes de eso, solo crean nodos AST, que una vez pateados, generarán el SQL real (o el idioma que se está compilando) y ejecutarán la consulta.

Consulte this blog post para obtener una explicación más detallada de cómo se hace esto.

-1

quizá poco demasiado tarde, pero se puede utilizar un hash:

@person = Person.where({name: "Jason", age: 26}) 

resultante consulta:

SELECT "person".* FROM "person" WHERE "person"."name" = 'Jason' AND "person"."age" = 26 
Cuestiones relacionadas