views:

24

answers:

3

If I have something like this:

class Post < ActiveRecord::Base
  has_many :comments, :as => :commentable do
    def approved
      find(:all, :conditions => {:approved => true})
    end
  end
end

class Comment < ActiveRecord::Base
  belongs_to :commentable, :polymorphic => true
end

...when I do this, I get 2 hits to the database (not including finding the post :p):

post = Post.first
post.comments #=> [Comment1, Comment2...]
post.comments.approved #=> [Comment1, Comment7...]

It seems like it should just filter the current comments array in memory, no? Is it doing that? Reason I ask is because the console shows SELECT * FROM ... on post.comments.approved, even though I already called post.comments. Shouldn't this be better optimized in ActiveRecord?

+1  A: 

It's optional, as in some cases you might only want to load the associated objects when needed. If you want them all loaded into memory, you need to explicitly declare the objects you'd like included with the initial query, using the :include flag. Example:

post = Post.find(:first, :include => :comment)

You might have to rewrite your extension to take advantage of the feature... an approach would be to change your "approved" function to iterate through the comments array attached to each post, and return a new array with the nonapproved comments filtered out. The "find" you have defined explicitly goes back to the database.

Joshua
A: 

The AR executes a new query for any finder calls inside a association extension method. You can refer to the cached result set by using self.

  has_many :comments, :as => :commentable do
    def approved
      # uses the cached result set
      self.select{|c| c.approved == true}
    end
  end
KandadaBoggu
A: 

If your query is really that simple, then what you want is a named scope:

class Comment
  named_scope :approved, :conditions => {:approved => true}
end

Then, you can do:

@post.comments.approved.count #=> 1 DB hit!
@post.comments.count #=> Another DB hit - can't reuse same scope

Look at #scope (#named_scope in Rails 2.3).

François Beausoleil