2012-03-01 7 views
5

Consentitemi di visualizzarlo per voi.In che modo ActiveRecord rileva l'ultimo metodo di chiamata in catena?

class Product < ActiveRecord::Base 
end 

Product.first.title 
#=> "My sample product" 

Niente di straordinario qui. Solo una semplice chiamata di metodo. Ora dai un'occhiata al seguente esempio.

class Product < ActiveRecord::Base 
    def method_missing 
    end 
end 

Product.first.title 
#=> nil 

Product.first 
Product.first.title 
#=> "My sample product" 

Com'è possibile? In qualche modo determinano la fine della catena del metodo e agiscono in tal senso? Almeno questa è la mia teoria.

Qualcuno può spiegare questo comportamento?

risposta

7

Stai vedendo un artefatto dell'uso di irb per investigare.

Quando si dice questo:

> Product.first.title 
#=> nil 

tuo method_missing sarà chiamata a lazy-caricare il metodo title e si ottiene nil.

Quando si dice questo:

> Product.first 

Stai efficacemente facendo questo:

> p = Product.first; puts p.inspect 

La prima istanza del prodotto verrà caricato e poi irb chiamerà inspect su di esso e AR aggiungerà la metodi di accesso lungo la strada. Il risultato è che il prodotto ora avrà un metodo title. Quindi, fare questo:

> Product.first 
> Product.first.title 

non chiamerà il method_missing a tutti come ci sarà un vero e proprio metodo di title per Product.first.title per chiamare.

Se si tenta ancora una volta come questo:

> Product.first; nil 
> Product.first.title 

vedrete due nil s.


Per quanto riguarda il concatenamento va, ActiveRecord in realtà non rilevare la fine, è solo che alcune chiamate di metodo, naturalmente, richiede dati reali dal database e alcuni non lo fanno.

Se si chiama where, order, o uno qualsiasi degli altri metodi di interrogazione, si ottiene un'istanza ActiveRecord::Relation indietro e si può catena più metodi di query e gli ambiti su quell'oggetto relazione. Ad esempio, where (che ActiveRecord :: Relation ottiene includendo ActiveRecord::QueryMethods) si presenta così:

def where(opts, *rest) 
    return self if opts.blank? 

    relation = clone 
    relation.where_values += build_where(opts, rest) 
    relation 
end 

quindi rende solo una copia della query corrente, aggiunge alcune cose per la copia, e ti dà la copia indietro.

Se si chiama first, last, to_a, all, uno qualsiasi dei metodi Enumerable (vale a dire si chiama each), ...quindi stai chiedendo istanze specifiche e ActiveRecord dovrà eseguire la query per realizzare l'istanza del modello in questione. Ad esempio, ActiveRecord::Relation#to_a assomiglia a questo:

def to_a 
    logging_query_plan do 
    exec_queries 
    end 
end 

e all è poco più di un wrapper to_a.

ActiveRecord non sa veramente dove si trova la fine della catena, non carica nulla dal database finché non lo ha, così gli dici dove finisce la catena dicendo vai avanti e recuperami alcuni dati.

+0

penso che rilevi la fine della catena: è dove non si ottiene un oggetto proxy finder! – phoet

+0

Questa non è la domanda. La domanda è: perché '' 'Product.first.title''' restituisce' '' nil''' finché viene chiamato '' 'Product.first''', quando' '' method_missing''' viene usato all'interno di un modello. Una volta chiamato '' 'Product.first''', il titolo restituisce' '' My sample blog'''. – user544941

+0

@ user544941: Ah, vedo cosa sta chiedendo: cosa sta sostituendo o bypassando il suo 'method_missing'. –

Problemi correlati