Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Eager loading associations on ActiveModel instances in Rails

In RoR, it is pretty common mistake for new people to load a class and assiocations like this# the solution to eager load

# The bellow generates an insane amount of queries
# post has many comments
# If you have 10 posts with 5 comments each
# this will run 11 queries 
posts = Post.find(:all)
posts.each do |post|
  post.comments
end

The solution is pretty simple to eager load

# should be 2 queries
# no matter how many posts you have
posts = Post.find(:all, :include => :comments) # runs a query to get all the comments for all the posts
posts.each do |post|
  post.comments # runs a query to get the comments for that post
end

But what if you don't have access to the class methods, and only have access to a collection of instance methods.

Then you are stuck with the query intensive lazy loading.

Is there a way to minimize queries to get all the comments for the collection of posts, from the collection of instances?

Addition for Answer (also added to the code above)


So to eager load from what I can see in the rdoc for rails is a class method on any extension of ActiveRecord::Associations, the problem is say you you don't have the ability to use a class method, so you need to use some sort of instance method

a code example of what I think it would look like would be is something like

post = Posts.find(:all)
posts.get_all(:comments) # runs the query to build comments into each post without the class method.
like image 502
austinbv Avatar asked Dec 17 '11 20:12

austinbv


1 Answers

In Rails 3.0 and earlier you can do:

Post.send :preload_associations, posts, :comments

You can pass arrays or hashes of association names like you can to include:

Post.send :preload_associations, posts, :comments => :users

In Rails 3.1 this has been moved and you use the Preloader like this:

ActiveRecord::Associations::Preloader.new(posts, :comments).run()

And since Rails 4 its invocation has changed to:

ActiveRecord::Associations::Preloader.new.preload(posts, :comments)
like image 169
Frederick Cheung Avatar answered Sep 18 '22 10:09

Frederick Cheung