Typically, when we wish to loop with a ruby Activerecord object, we follow something like below :
class CommentsController < ApplicationController def users_comments posts = Post.all comments = posts.map(&:comments).flatten @user_comments = comments.select do |comment| comment.author.username == params[:username] end end end While above will be correct and won't create any issue as such, but this will result in multiple unnecessary calls to Database. This is a classic case of what we call "n+1" BUG.The first line will retrieve all records of the
Posts table in Post objectfrom the database, but then next line will make an additional request for each
Post objectto fetch the corresponding
Commentobjects related to that relevant Post. To make matters worse, this code is then making even more database requests in order to retrieve the
Comment of each Post.
This can all be avoided by changing the first line in the method to:
posts = Post.includes(comments: [:author]).all
This tells ActiveRecord to retrieve the corresponding
Author records from the database immediately after the initial request for all
Posts, thereby reducing the number of database requests to just three.
Please note that the above solution is only one of a few ways that it is possible to avoid incurring an “n+1” penalty, and each alternative will have its own besr and worse cases. The above answer is shared since it requires the smallest change to the existing code and makes no assumptions regarding the reverse association of
Apparently, there’s another issue here (although not what we’re focused on in this question and answer); namely, performing a query in Ruby that could instead be done in the database (and which would very likely be faster there!). A relatively complex query like this can instead be constructed in ActiveRecord pretty easily, thus turning a 3 database query operation (plus some Ruby code executing) into a single database query.
Hopefully this will help you in using your loops to a better extent and reduce usage of plain/default Object.all method.