Estás viendo un artefacto de usar irb
para investigar cosas.
Cuando se dice esto:
> Product.first.title
#=> nil
Su method_missing
se llamará a lazy-cargar el método title
y se obtiene nil
.
Cuando se dice esto:
> Product.first
Estás haciendo efectivamente esto:
> p = Product.first; puts p.inspect
La primera instancia del producto se cargará y luego irb
llamará inspect
en él y AR añadirá el métodos de acceso en el camino. El resultado es que el Producto ahora tendrá un método title
. Por lo tanto, hacer esto:
> Product.first
> Product.first.title
no llamará a su method_missing
en absoluto, ya que habrá un verdadero método para title
Product.first.title
llamar.
si intenta de nuevo como esto:
> Product.first; nil
> Product.first.title
verás dos nil
s.
En lo que va de encadenamiento, ActiveRecord en realidad no detectar el final, es sólo que algunos método llama, naturalmente, requiere datos reales de la base de datos y otros no.
Si llama where
, order
, o cualquiera de los otros métodos de consultas, de obtener una instancia ActiveRecord::Relation atrás y se pueden encadenar más métodos de consulta y alcances en ese objeto relación. Por ejemplo, where
(que ActiveRecord :: Relation obtiene mediante la inclusión de ActiveRecord::QueryMethods) tiene el siguiente aspecto:
def where(opts, *rest)
return self if opts.blank?
relation = clone
relation.where_values += build_where(opts, rest)
relation
end
lo que sólo tiene una copia de la consulta actual, añade algunas cosas para la copia, y le da la copia espalda.
Si llama first
, last
, to_a
, all
, cualquiera de los métodos Enumerable (es decir, se llama a each
), ...luego pregunta por instancias específicas y ActiveRecord tendrá que ejecutar la consulta para realizar las instancias del modelo en cuestión. Por ejemplo, ActiveRecord::Relation#to_a
se parece a esto:
def to_a
logging_query_plan do
exec_queries
end
end
y all
es poco más que una envoltura alrededor de to_a
.
ActiveRecord realmente no sabe dónde está el final de la cadena, simplemente no carga nada desde la base de datos hasta que lo tiene que decir para que la cadena termine diciendo vaya y recíbeme algunos datos.
Creo que detecta el final de la cadena: ¡es donde no se obtiene un objeto proxy buscador! – phoet
Esto no es de lo que se trata la pregunta. La pregunta es por qué '' 'Product.first.title''' devuelve' '' nil''' hasta que se invoca '' 'Product.first''', cuando' '' method_missing''' se usa dentro de un modelo. Una vez que haya llamado '' 'Product.first''' title, devuelve' '' My sample blog'''. – user544941
@ user544941: Ah, veo por qué pregunta: qué está reemplazando o eludiendo su 'method_missing'. –