ユーザーが 10 件の投稿をした場合、これは技術的にデータベース呼び出しを 10 回行うことになりますか?
いいえ。
myUser = User.find 123
myUser.posts.each do |post|
puts post.title
end
このコードは、2 つのクエリを実行します。1 つ目は ID でユーザーを検索し、単一の行を返します。2 つ目は、一致するユーザー ID を持つすべての投稿を求めるクエリを実行しますmyUser
。次に、each
その結果を使用して反復します。
開発モードでログを見ると、実行中のクエリが表示され、それらすべての投稿を返す単一のクエリが表示されるはずです。
Rails は関連付けプロキシ オブジェクトを使用してクエリを保持し、レコードが必要なときにクエリを実行して、結果をキャッシュします。これは非常に役立つコードであり、ほとんどの場合、このようなことを処理します。
これはRuby ではなくRailsの機能です。
ruby レベルでは、each
単にコレクションに作用します。
def get_letters
puts 'executing "query"'
sleep(3)
["a","b","c"]
end
get_letters.each do |item|
puts item
end
これは印刷されるはずです。
executing "query"
a
b
c
get_letters
メソッドが実行されると、配列が返されます。この配列には、既にデータが格納されているため、メソッドを呼び出して、各each
アイテムを処理できます。コレクションのフェッチと反復処理は、2 つの完全に別個のステップです。
ペーストビンから:
# will this run forever?
myArr = ["a","b","c"]
myArr.each do |item|
myArr.push("x")
end
ええ、そうなりますが、配列がオーバーオーバーで「フェッチ」されているためではありません。
これは、このような JavaScript と同等であり、より適切に綴られています。
myArr = ["a","b","c"];
for (var i = 0; i < myArr.length; i++) {
myArr.push('x');
}
元の配列は、ループの各反復で、まだ完了しているかどうかを確認します。しかし、配列はアイテムが 1 つ進むたびに 1 つ長くなるため、反復ごとに両方が 1 つ増加するため、i < myArr.length
常に長くなります。同じ理由で、true
あなたのループでルビーでも同じことが起こっています。each
配列を再生成するためにいくつかのコードを実行し続けるためではなく、永久に実行されます。結果の配列を人為的に変更しているため、永久に実行されます。