如何使用Rails和Ancestry对模型后代进行预先加载

时间:2015-08-25 14:57:08

标签: ruby-on-rails eager-loading ancestry

至于现在,我正在开发一个博客应用程序,其中包含通过has_many / belongs_to关联连接的文章/评论模型。要创建嵌套注释功能,我使用祖先gem。但是,我想热切地加载评论的所有后代。有什么想法如何处理这个? 我尝试使用 join where 但似乎他们生成了n + 1个查询。 以下是我如何调用方法在视图中显示它们。

<%= nested_comments_display comments.arrange(:order => :created_at) %>

这是 nested_comments_display 方法

def nested_comments_display(comments)
  comments.map do |comment, sub_comments|
    render(comment) + content_tag(:div,nested_comments_display(sub_comments), 
                                :class => "nested_comment")
  end.join.html_safe
end

我也使用了decent_exposure gem,我的CommentsController看起来像这样

class CommentsController < ApplicationController

  expose(:article)
  expose(:comments, ancestor: :article) 
  expose(:comment, attributes: :comment_params)

  ....
end

1 个答案:

答案 0 :(得分:2)

解决这个问题最简单的方法(我知道),就是创建一个包含预先加载的整个子树集合的对象,然后只是从内存中的对象中请求孩子......

class CachedAncestryCollection
  def initialize(collection)
    @collection = collection.to_a
  end

  def children_for(parent_id = nil)
    @collection.select do |node|
     parent_id ? (node.ancestry && node.ancestry.match(/#{parent_id}$/)) : node.ancestry.nil?
    end
  end
end

# ...

preloaded_subtree = Comment.where(:id => comments.map(&:subtree_ids))
cached = CachedAncestryCollection.new(preloaded_subtree)

def nested_comments_display(cached, parent_id = nil)
  content_tag(:div) do
    cached.children_for(parent_id).map do |child|
      nested_comments_display(cached, child.id)
    end
  end
end