Flowdock
method

preload_associations

Importance_4
v2.2.1 - Show latest stable - 2 notes - Class: ActiveRecord::AssociationPreload::ClassMethods
preload_associations(records, associations, preload_options={}) protected

Eager loads the named associations for the given ActiveRecord record(s).

In this description, ‘association name’ shall refer to the name passed to an association creation method. For example, a model that specifies belongs_to :author, has_many :buyers has association names :author and :buyers.

Parameters

records is an array of ActiveRecord::Base. This array needs not be flat, i.e. records itself may also contain arrays of records. In any case, preload_associations will preload the associations all records by flattening records.

associations specifies one or more associations that you want to preload. It may be:

  • a Symbol or a String which specifies a single association name. For example, specifiying :books allows this method to preload all books for an Author.
  • an Array which specifies multiple association names. This array is processed recursively. For example, specifying [:avatar, :books] allows this method to preload an author’s avatar as well as all of his books.
  • a Hash which specifies multiple association names, as well as association names for the to-be-preloaded association objects. For example, specifying { :author => :avatar } will preload a book’s author, as well as that author’s avatar.

:associations has the same format as the :include option for ActiveRecord::Base.find. So associations could look like this:

  :books
  [ :books, :author ]
  { :author => :avatar }
  [ :books, { :author => :avatar } ]

preload_options contains options that will be passed to ActiveRecord#find (which is called under the hood for preloading records). But it is passed only one level deep in the associations argument, i.e. it’s not passed to the child associations when associations is a Hash.

Show source
Register or log in to add new notes.
August 19, 2008 - (v2.1.0)
8 thanks

preload_associations manually

Usually you preload associations using :include => [ ... ]. In Rails 2.1 each association is fetched with a separate query. Something like:

Post.find(:all, :include => [:tags, :user])

will produce 3 queries - each for posts, tags and users.


But sometimes you have a complex query, which uses :joins => :other_association and conditions between multiple tables, but not the ones you need to include. Then everything is mixed back in one query like in old versions of Rails.

Another case may be when it is not possible to use :include at all, for example while using find_by_sql, but you still want/need to preload associated records.

In rails 2.1 find uses preload_associations internally, when it is possible (There are no joins or conditions between tables).

So then you can preload asociations manually from within your model:

class Post < ActiveRecord::Base

has_many :tags
belongs_to :user
...

def self.find_complex_with_includes
  posts = find_by_sql(...) # or find(:all, :joins => .....)
  preload_associations(posts, [:tags, :user])
  posts
end

end

and then do

@posts = Post.find_complex_with_includes

February 6, 2009 - (>= v2.1.0)
1 thank

Whacky edge case

The above works great as long as you select the primary key of the owning assocations.

preload_associations calls a group_by on that object so if there is no primary key attributed filled out it will reduce the records to 1 object. ex: rows = foo.find(:all,:select=>“boo.id, foo.name, foo.age, count(DISTINCT foo.id)”, :group=>“foo.name,foo.age having count( DISTINCT foo.id) > 1”,:joins=>“INNER JOIN bar.foo on bar.foo_id = foo.id”)

preload_assications(rows,:bar)

rows.first.bar.name #=> sql call already made in preload rows.last.bar.name #=> just made another sql call to get bar

fix: :select=>“foo.id, boo.id, foo.name, foo.age, count(DISTINCT foo.id)”

now preload_associations will include all the ids found instead of just the 1st one.