Se l'utente aveva 10 post, questo sarebbe tecnicamente fare una chiamata di database 10 volte?
No.
myUser = User.find 123
myUser.posts.each do |post|
puts post.title
end
Questo codice eseguirà 2 query. Il primo troverà un utente con il suo id, restituendo una singola riga. Il secondo eseguirà una query che richiede tutti i post che hanno un ID utente che corrisponde a myUser
. Quindi il each
utilizzerà il risultato di questo per scorrere.
Se si guarda il registro in modalità di sviluppo che ti dice le query è in esecuzione, e si dovrebbe vedere una singola query di ritorno tutti quei post.
Rails utilizza un oggetto proxy di associazione per contenere la query, eseguire la query quando sono necessari i record e quindi memorizza nella cache il risultato. È un bit di codice molto utile e, per la maggior parte, gestisce cose come questa per te.
Questa è una funzionalità di Rails, non rubino.
A livello rubino, each
agisce semplicemente su collezioni.
def get_letters
puts 'executing "query"'
sleep(3)
["a","b","c"]
end
get_letters.each do |item|
puts item
end
Questo dovrebbe essere stampato.
executing "query"
a
b
c
Procedimento get_letters
esegue, restituisce una matrice, una tale matrice già pieno di dati è quello che chiamiamo il metodo each
su, così possiamo elaborare ogni elemento. Recuperare la raccolta e iterare attraverso di essa sono 2 passaggi completamente separati.
Dal tuo pastebin:
# will this run forever?
myArr = ["a","b","c"]
myArr.each do |item|
myArr.push("x")
end
Sì lo farà, ma non perché la matrice è essere "recuperato" su un over.
Equivalente a javascript come questo, che lo spiega meglio.
myArr = ["a","b","c"];
for (var i = 0; i < myArr.length; i++) {
myArr.push('x');
}
L'array originale, su ogni iterazione dei controlli di ciclo per vedere se è ancora finito. Ma poiché l'array si allunga di una unità ogni volta che avanza di un elemento, i < myArr.length
sarà sempre true
perché entrambi aumentano di uno su ogni iterazione. La stessa cosa sta succedendo in ruby con il tuo ciclo each
, per lo stesso motivo.
Viene eseguito per sempre, non perché si continua a eseguire codice per rigenerare l'array. Funziona all'infinito perché stai modificando artificialmente la matrice risultante.
Grazie, ma domanda. Nel mio cestino della pasta come ultimo esempio, il ciclo gira per sempre ... Non capisco perché sarebbe se il risultato fosse "memorizzato nella cache" Ruby modificasse la cache in seguito? Cosa succederebbe se aggiungessi un post in un ciclo di post di .each? – K2xL
@ K2xL Vedi la mia modifica, che spiega di più le cose sul livello base ruby (non rails). Ma il tuo ciclo, come pubblicato, sicuramente non è "correre per sempre". Dopo 3 secondi, è fatto. –
Vedere la mia modifica (ho accidentalmente inviato l'URL pastebin errato) – K2xL