Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Eager loading of polymorphic associations in ActiveRecord

This is my first time using Rails and I was wondering if it's possible to load a has one polymorphic association in one SQL query? The models and associations between them are basic enough: An Asset model/table can refer to a content (either an Image, Text, or Audio) through a polymorphic association, i.e.

class Asset < ActiveRecord::Base
  :belongs_to :content, :polymorphic => true
end

and the Image, Text, Audio are defined like this:

class Image < ActiveRecord::Base
  :has_one :asset, :as => :content
end

When I try to load an Image, say like this:

Image.first(
      :conditions => {:id => id},
      :include => :asset
)

It specifies two queries, one to retrieve the Image and another to retrieve the Asset (FYI, this happens also if I specify a :joins). Based on my understanding, ActiveRecord does this because it doesn't know there's a one-to-one association between Image and Asset. Is there a way to force a join and retrieve the 2 objects in one go? I've also tried using join with a custom select, but I end up having to create the ActiveRecord models manually and their associations.

Does ActiveRecord provide a way to do this?

like image 940
Wayne See Avatar asked Sep 25 '09 04:09

Wayne See


People also ask

How is polymorphic association set up in Rails?

The basic structure of a polymorphic association (PA)sets up 2 columns in the comment table. (This is different from a typical one-to-many association, where we'd only need one column that references the id's of the model it belongs to). For a PA, the first column we need to create is for the selected model.

What is eager loading rails?

Eager loading lets you preload the associated data (authors) for all the posts from the database, improves the overall performance by reducing the number of queries, and provides you with the data that you want to display in your views, but the only catch here is which one to use. Gotcha!

What is polymorphic association in Ruby on Rails?

Polymorphic relationship in Rails refers to a type of Active Record association. This concept is used to attach a model to another model that can be of a different type by only having to define one association.


2 Answers

After digging through the Rails source I've discovered that you can force a join by referencing a table other than the current model in either the select, conditions or order clauses.

So, if I specify an order on the Asset table:

Image.first(
      :conditions => {:id => id},
      :include => :asset,
      :order => "asset.id"
)

The resulting SQL will use a left outer join and everything in one statement. I would have preferred an inner join, but I guess this will do for now.

like image 94
Wayne See Avatar answered Oct 20 '22 19:10

Wayne See


I ran up against this issue myself. ActiveRecord leans more toward the end of making it easy for Rubyists (who may not even be all too familiar with SQL) to interface with the database, than it does with optimized database calls. You might have to interact with the database at a lower level (e.g. DBI) to improve your performance. Using ActiveRecord will definitely affect how you design your schema.

The desire for SQL efficiency got me thinking about using other ORMs. I haven't found one to suit my needs. Even those that move more toward transact SQL itself (e.g. Sequel) have a heavy Ruby API. I would be content without a Ruby-like API and just manually writing my T-SQL. The real benefit I'm after with an ORM is the M, mapping the result set (of one or more tables) into the objects.

like image 31
Mario Avatar answered Oct 20 '22 19:10

Mario