铁路祖先分页

时间:2011-06-07 06:25:26

标签: ruby-on-rails-3 tree will-paginate paginate

我刚刚关注了Railscast教程:

http://railscasts.com/episodes/262-trees-with-ancestry

是否有可能对Ancestry的结果进行分页? 例如:鉴于我在Message控制器中有以下内容:

def index
  @messages = Message.arrange(:order => :name)
end

然后我将如何对其进行分页,因为它会导致哈希?

更新 我发现,如果我使用.keys,那么它会分页,但只有顶级而不是孩子。

Message.scoped.arrange(:order => :name).keys

更新 每条消息都有一个代码和一些内容。我可以有嵌套的消息

假设我有

代码 - 名称

1 - Test1
  1 - test1 sub1
  2 - test1 sub2
2 - Test2
  1 - test2 sub1
  2 - test2 sub2
  3 - test2 sub3

这就是我想要显示列表的方式,但我也希望对这个已排序的树进行分页。

1 个答案:

答案 0 :(得分:4)

这是可能的,但我只是设法使用两次数据库旅行。

主要问题源于无法对节点的子节点设置限制,这导致节点的子节点被截断或子节点在后续页面上被孤立。

一个例子:

id: 105, Ancestry: Null
id: 117, Ancestry: 105
id: 118, Ancestry: 105/117
id: 119, Ancestry: 105/117/118

限制0,3(为了上面的示例)将返回前三个记录,这将记录除id:119以外的所有记录。随后的LIMIT 3,3将返回id:119,由于父母不在场,因此无法正确呈现。

我采用的一种解决方案是使用两个查询:

  1. 第一个只返回根节点。这些可以进行排序,这是分页的查询。
  2. 根据第一个查询发出第二个查询,该查询返回分页父项的所有子项。您应该能够按级别对孩子进行排序。
  3. 就我而言,我有一个Post模型(has_ancestry)。每个帖子都可以有任何级别的回复。邮件对象也有一个回复计数,它是其直接子项的缓存计数器。

    在控制器中:

    roots  = @topic.posts.roots_only.paginate :page => params[:page]
    @posts = Post.fetch_children_for_roots(@topic, roots)
    

    在Post模型中:

    named_scope :roots_only, :conditions => 'posts.ancestry is null'
    
    def self.fetch_children_for_roots(postable, roots)
      unless roots.blank?
        condition = roots.select{|r|r.replies_count > 0}.collect{|r| "(ancestry like '#{r.id}%')"}.join(' or ')
        unless condition.blank?
          children = postable.posts.scoped(:from => 'posts FORCE INDEX (index_posts_on_ancestry)', :conditions => condition).all
          roots.concat children
        end
      end
      roots
    end
    

    一些注意事项:

    • 如果使用多个LIKE语句,MySQL将停止使用祖先列索引。 FORCE INDEX强制mySQL使用索引并阻止全表扫描
    • LIKE语句仅为具有直接子节点的节点构建,因此replies_count列派上用场
    • 类方法的作用是将子项追加到root,这是一个WillPaginate :: Collection

    最后,可以在您的视图中管理这些内容:

      =will_paginate @posts  
      -Post.arrange_nodes(@posts).each do |post, replies|
        =do stuff here
    

    这里的关键方法是 arrange_nodes ,它是从祖先插件和模型中混合而来的。这基本上是一个排序的节点数组,并返回一个已排序和分层的哈希。

    我很欣赏这种方法并没有直接解决您的问题,但我希望通过调整可以对您的案例应用相同的方法。

    这可能是一种更优雅的方式,但总的来说我对解决方案感到满意(直到有更好的解决方案出现)。