Eager loading ActiveRecord objects

I have a complex graph of ActiveRecord entities that I want to load with
one big honkin’ join query to avoid ripple loading. It’s for a report.
However :include doesn’t get me all the way there because I want to load
parents of parents (or children of children). I don’t mind doing the
SQL by hand but I’m not quite sure what to do to get the result set into
my model objects. I don’t want to bypass my model objects because they
have important calculation methods I need.

I’d like to run a raw SQL query and then somehow plug the results into
model objects. Sooo, what’s the best way to go about this?

Thanks!

Steve

Stephen M. wrote:

However :include doesn’t get me all the way there because I want to load
parents of parents (or children of children). I don’t mind doing the
SQL by hand but I’m not quite sure what to do to get the result set into
my model objects. I don’t want to bypass my model objects because they
have important calculation methods I need.

You can load children of children with :include, eg
Foo.find :all, :include =>[:{children=>[:children_of_children]}]

Frederick C. wrote:

You can load children of children with :include, eg
Foo.find :all, :include =>[:{children=>[:children_of_children]}]

Awesome, thanks! I’m not sure if I understand the syntax. Are the
curly braces necessary?

Steve

Stephen M. wrote:

Frederick C. wrote:

You can load children of children with :include, eg
Foo.find :all, :include =>[:{children=>[:children_of_children]}]

Awesome, thanks! I’m not sure if I understand the syntax. Are the
curly braces necessary?

Steve

Slight typo: should be
Foo.find :all, :include =>[{:children=>[:children_of_children]}]

IIRC you do need the braces generally, although you can probably omit
for the example above. You do need them for stuff like
Foo.find :all, :include =>[{:children=>[:children_of_children]},
:other_attribute]

Thanks again. Sounds like I’ve got an ActiveRecord guru here.

Related question: Can I join and include the same table? I want to
filter based on a condition in the joined table, but I also want to
eagerly load that table. Ideally I’d like to do that with just one join
in the generated SQL. Can I refer to included tables (via :include) in
my :conditions clause?

Steve

Stephen M. wrote:

Thanks again. Sounds like I’ve got an ActiveRecord guru here.
You’re just to lucky to stumble onto one of the things I have worked
out.

Related question: Can I join and include the same table? I want to
filter based on a condition in the joined table, but I also want to
eagerly load that table. Ideally I’d like to do that with just one join
in the generated SQL. Can I refer to included tables (via :include) in
my :conditions clause?

Steve

I’ve never tried :join and :include of the same table (which I suspect
would be counter productive), however I have used the :included tables
in the :conditions parameter without any problems. The only thing you
need to be careful about is that you have to disambiguate all the column
names (eg foos.bar = ‘baz’ instead of bar = ‘baz’)

Fred

Frederick C. wrote:

I’ve never tried :join and :include of the same table (which I suspect
would be counter productive), however I have used the :included tables
in the :conditions parameter without any problems. The only thing you
need to be careful about is that you have to disambiguate all the column
names (eg foos.bar = ‘baz’ instead of bar = ‘baz’)

OK will do. Thanks again!

Steve

Frederick C. wrote:

Stephen M. wrote:

Frederick C. wrote:

You can load children of children with :include, eg
Foo.find :all, :include =>[:{children=>[:children_of_children]}]

Awesome, thanks! I’m not sure if I understand the syntax. Are the
curly braces necessary?

Steve

Slight typo: should be
Foo.find :all, :include =>[{:children=>[:children_of_children]}]

IIRC you do need the braces generally, although you can probably omit
for the example above. You do need them for stuff like
Foo.find :all, :include =>[{:children=>[:children_of_children]},
:other_attribute]

I’m getting a syntax error here - no doubt something stupid:

@guidance_group=GuidanceGroup.find(@params[:guidance_group_id],
:include=>[{:pupils=>[:setlinks], :pupil_sets, :guidance_group, \
:academic_year]})

RadRails is pointing to the comma after :pupil_sets

Can anyone see the problem?

Cheers,

Robert J.

I think you have an extra ] after :setlinks and an extra [ at the start.
Try
this out.

@guidance_group=GuidanceGroup.find(@params[:guidance_group_id],
:include=>{:pupils=>[:setlinks, :pupil_sets, :guidance_group,
:academic_year]})

Frederick C. wrote:

Stephen M. wrote:

Frederick C. wrote:

You can load children of children with :include, eg
Foo.find :all, :include =>[:{children=>[:children_of_children]}]

Awesome, thanks! I’m not sure if I understand the syntax. Are the
curly braces necessary?

Steve

Slight typo: should be
Foo.find :all, :include =>[{:children=>[:children_of_children]}]

IIRC you do need the braces generally, although you can probably omit
for the example above. You do need them for stuff like
Foo.find :all, :include =>[{:children=>[:children_of_children]},
:other_attribute]

Awesome +1 ! I was just about to post a question about exactly this
issue, and here is the answer. Some days I just love the Internet :slight_smile:

Robert J.

@guidance_group=GuidanceGroup.find(@params[:guidance_group_id],
:include=>[{:pupils=>[:setlinks], :pupil_sets, :guidance_group, \
:academic_year]})

RadRails is pointing to the comma after :pupil_sets

It’s telling you that because it thinks you’re in a hash: it’s expecting
a =>.
You’re best placed to know what you actually mean, but i suspect you
actually want
:include => [{:pupils=>[:setlinks]}, :pupils_sets, :guidance_group,
:academic_year]
(assuming :setlinks is an attribute of each pupil and everything else is
an attribute of GuidanceGroup)

Using include on the same table works just fine. For one of my
applications
I have a table projects, which references itself because projects can
have
subprojects which can have more subprojects, etc…

class Project < ActiveRecord::Base

Project.find :all, :include => :child_projects

Sorry, accidently hit send before I was done…

class Project < ActiveRecord::Base
belongs_to :parent_project, :class_name => ‘Project’, :foreign_key =>
‘parent_project_id’
has_many :child_project, :class_name => ‘Project’, :foreign_key =>
‘parent_project_id’
end

Project.find :all, :include => :child_projects

This works just fine and I am able to load any project, with all child
projects in one sql query.

Frederick C. wrote:

@guidance_group=GuidanceGroup.find(@params[:guidance_group_id],
:include=>[{:pupils=>[:setlinks], :pupil_sets, :guidance_group, \
:academic_year]})

RadRails is pointing to the comma after :pupil_sets

It’s telling you that because it thinks you’re in a hash: it’s expecting
a =>.
You’re best placed to know what you actually mean, but i suspect you
actually want
:include => [{:pupils=>[:setlinks]}, :pupils_sets, :guidance_group,
:academic_year]
(assuming :setlinks is an attribute of each pupil and everything else is
an attribute of GuidanceGroup)

Cheers - that works. The reference to guidance_group as a child of
guidance_group is as mysterious to me as to everyone else. Just a slip
of the fingers :slight_smile:

BTW, the reason I want to eager load absolutely everything is that the
report I am creating is going to be hived off to a BackgrounDrb worker.
I want to get all the ActiveRecord work done in the background, so that
the rendering is done as quickly as possible once the worker has done
its job.

Robert J.