views:

167

answers:

1

I have a number of custom find_by_sql queries in Rails. I would like to use eager loading with them but there doesn't seem to be a good way to do this.

I have seen the eager_custom.rb file floating around and it doesn't seem to work with Rails now. It appear Rails does eager loading differently now, using 2 queries (the regular query plus a query where the 'id IN' the ids from the first query), instead of the single join query used in the past.

My question is if I do a custom SQL query, then do 'id IN' query, is there a way to add back associated objects into the initial query results?

For example I have topics loaded with find_by_sql, then I find topic images where the topic id is in the topics ids, is there a way to add the images manually back to the topics?

Thanks

+3  A: 

As you noticed, in Rails 2.1 a new kind of eager/pre-loading was introduced which uses multiple queries with id IN (...). This method is usually faster, especially when there are multiple associations being pre-loaded. You can use this functionality manually with find_by_sql by using the preload_associations class method inherited from ActiveRecord (not recommended). For example:

class Person
  def self.find_a_special_group
    people = find_by_sql("...")
    preload_associations(people, [:jobs, :addresses])
    return people
  end
end

The preload_associations method is protected, so you must call it from within the class, and it takes (1) an array of objects, (2) an array, hash, or symbol of associations (same format as find's :include option), and (3) an options hash. See the documentation for the ActiveRecord::AssociationPreload::ClassMethods module for more details.

However, having said all of that, this technique is certainly undesirable as the Rails documentation discourages programmers from using preload_associations directly. Are you sure you have to use find_by_sql? Are you sure you know all of the options find takes? (:select, :from, :joins, :group, :having, etc) I'm not saying you don't need find_by_sql, but it might be worth a few minutes to make sure.

Alex Reisner
This is perfect, thanks very much. I would prefer not to use find_by_sql but I have a number of very complex queries.