如何在ActiveRecord的父对象中进行memoize?

时间:2014-01-13 09:47:41

标签: ruby-on-rails activerecord memoization

如何在父对象中记忆昂贵的查询并在子对象中重用它?我面临的问题是,每次我从子到父:child1.parent或child2.parent进行引用时,它会给出不同的对象id,并且不会发生memoization。

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

这应该只查询一次评论,但因为它没有记录在同一个对象上,所以它加载了两次

Loading comments...
Loading comments...

2 个答案:

答案 0 :(得分:1)

尝试此帖子= Post.last(include: :comments)此语句急切加载关系现在执行操作post.comments[0]这不会触发任何SQL查询,因为相关记录已经存在

答案 1 :(得分:1)

有几种方法可以做到:

<强> 1。使用ActiveRecord Association Extensions

class Post
  has_many :comments do

      def total
          proxy_association.target.size
      end

  end
end

允许您调用proxy_association对象,并将该方法附加到comments的实例(以便您可以调用@post.comments.total


<强> 2。使用: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

允许您从selfself.post.total_comments

引用父对象

第3。使用“Eager Loading”(将对象保留在内存中)

这是查询级别,并且在NitinJ的答案中提到了&amp; this RailsCast

Post.includes(:comments)

我认为NitinJ的评论比我的好,因为我只有使用.includes创建数据库调用的经验(不在关联容量中使用它)


奖励 - Counter-Cache - 使用此代替comments.count - 它将计数存储在内存中,这将删除昂贵的数据库调用!