how to ? Rails 3 ActiveRecord eager loading and AREL

Hello everyone,

I would like to eager load scoped records to avoid queries executed in a
loop (huge performance impact).

The "scoped" part is what is giving me a hard time.

I'm using Rails3 RC.

Does anyone have any idea how I can do it?

Here is a test case : we have an "Article" and a "Comment" Activerecord
models,

article has many comments
comment belongs to article

Comment has a scope defined like this (app/models/comment.rb) :

Hello everyone,

I would like to eager load scoped records to avoid queries executed in a
loop (huge performance impact).

The "scoped" part is what is giving me a hard time.

Can you define a scope at class level, instead of defining a method?

scope :recent, where ["published_at >= ?", 2.days.ago]

Then when you later do

article.comments.recent

the join/include clauses should be chained together *first*, resulting
in max one query per article.

Jeff

Thanks for your replay Jeff.

Unfortunately, declaring my scope with the "scope" method instead of a
regular method returning an ActiveRecord::Relation doesn't solve my
problem. (it also creates a new one since "2.days.ago" is only evaluated
when the app loads the classes and not every time the method is called)

I think the includes method should support relations as well as
associations (since associations/scopes/relations are so well integrated
with eachother in rails 3).

That way the following :

  @articles = Article.includes(:comments => :recent)

would build the relation in a way that recent comments are eagerly
loaded (instead of complaining that comments have no association named
"recent")

Cheers,

M-Ryan

Unfortunately, declaring my scope with the "scope" method instead of a
regular method returning an ActiveRecord::Relation doesn't solve my
problem. (it also creates a new one since "2.days.ago" is only evaluated
when the app loads the classes and not every time the method is called)

He made a mistake. It should be:

scope :recent, lambda { where ["published_at >= ?", 2.days.ago] }

I think the includes method should support relations as well as
associations (since associations/scopes/relations are so well integrated
with eachother in rails 3).
That way the following :

@articles = Article.includes(:comments => :recent)

Ok, I see. You want to scope the eager-loaded objects. I guess this is
a case where Datamapper's identity map comes in handy.

I haven't tried this yet, but you might be able to put add scopes to
the association itself.

has_many :recent_comments, :class_name => "Comment", :conditions
=> ...

Hm, though that won't do the lazy eval. I checked the code for
has_many. The finder_sql is constructed the old way, not Arel all the
way down.

The compromise I can think of is to extend the collection code so it
loads all the comments in one batch and insert them into your
articles. The other one I can think of is to use AJAX to load the
recent comments and have a dedicated controller handle that. It's
probably a better design than trying to load a set of articles and
recent comments for all of them, in a single go, then rendering them
to the page.

Ho-Sheng Hsiao
http://ruby-lambda.blogspot.com