Question

How do i memoize an expensive query in parent object and reuse it in child objects? The problem i'm facing is that each time i make a reference from child to parent: child1.parent or child2.parent, it gives different object ids and memoization does not happen.

class Post
  has_many :comments
  def total_comments
    unless @total_comments
      puts "Loading comments"
      @total_comments = comments.count
    end
    @total_comments
  end
end

class Comment
  belongs_to :post
  def total_comments
    post.total_comments
  end
end

post.comments[0].total_comments
post.comments[1].total_comments

This should've queried for comments only once, but because it's not memoized on the same object it's loading twice

Loading comments...
Loading comments...
Était-ce utile?

La solution

Several ways to do it:

1. Use ActiveRecord Association Extensions

class Post
  has_many :comments do

      def total
          proxy_association.target.size
      end

  end
end

Allows you to call proxy_association object, and appends the method to the instance of comments (so you can call @post.comments.total)


2. Use :inverse_of

#app/models/post.rb
Class Post < ActiveRecord::Base
    has_many :comments, inverse_of: :post
end

#app/models/comment.rb
Class Comment < ActiveRecord::Base
    belongs_to :post, inverse_of: :comments
end

Allows you to reference parent object from self (self.post.total_comments)


3. Use "Eager Loading" (keeping objects in memory)

This is query-level, and alluded to in NitinJ's answer & this RailsCast:

Post.includes(:comments)

I think NitinJ's comments are better than mine here, as I only have experience in creating DB calls with .includes (not using it in an association capacity)


BONUS - Counter-Cache -- use this instead of comments.count - it stores the count in memory, which will remove an expensive DB call!

Autres conseils

Try this post =Post.last(include: :comments) this statement eager loads the relation now perform operation post.comments[0] this will not trigger any SQL query to find that as the associated records is already there

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top