Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>It is possible but I've only managed to do it using two database trips. </p> <p>The main issue stems from not being able to set limits on a node's children, which leads to either a node's children being truncated or children being orphaned on subsequent pages.</p> <p>An example:</p> <pre><code>id: 105, Ancestry: Null id: 117, Ancestry: 105 id: 118, Ancestry: 105/117 id: 119, Ancestry: 105/117/118 </code></pre> <p>A LIMIT 0,3 (for the sake of the example above) would return the first three records, which will render all but id:119. The subsequent LIMIT 3,3 will return id: 119 which will not render correctly as its parents are not present.</p> <p>One solution I've employed is using two queries:</p> <ol> <li>The first returns root nodes only. These can be sorted and it is this query that is paginated.</li> <li>A second query is issued, based on the first, which returns all children of the paginated parents. You should be able to sort children per level.</li> </ol> <p>In my case, I have a Post model (which has_ancestry) . Each post can have any level of replies. Also a post object has a replies count which is a cache counter for its immediate children.</p> <p>In the controller:</p> <pre><code>roots = @topic.posts.roots_only.paginate :page =&gt; params[:page] @posts = Post.fetch_children_for_roots(@topic, roots) </code></pre> <p>In the Post model:</p> <pre><code>named_scope :roots_only, :conditions =&gt; 'posts.ancestry is null' def self.fetch_children_for_roots(postable, roots) unless roots.blank? condition = roots.select{|r|r.replies_count &gt; 0}.collect{|r| "(ancestry like '#{r.id}%')"}.join(' or ') unless condition.blank? children = postable.posts.scoped(:from =&gt; 'posts FORCE INDEX (index_posts_on_ancestry)', :conditions =&gt; condition).all roots.concat children end end roots end </code></pre> <p>Some notes:</p> <ul> <li>MySQL will stop using the ancestry column index if multiple LIKE statements are used. The FORCE INDEX forces mySQL to use the index and prevents a full table scan</li> <li>LIKE statements are only built for nodes with direct children, so that replies_count column came in handy</li> <li>What the class method does is appends children to root, which is a WillPaginate::Collection </li> </ul> <p>Finally, these can be managed in your view:</p> <pre><code> =will_paginate @posts -Post.arrange_nodes(@posts).each do |post, replies| =do stuff here </code></pre> <p>The key method here is <strong>arrange_nodes</strong> which is mixed in from the ancestry plugin and into your model. This basically takes a sorted Array of nodes and returns a sorted and hierarchical Hash.</p> <p>I appreciate that this method does not directly address your question but I hope that the same method, with tweaks, can be applied for your case.</p> <p>There is probably a more elegant way of doing this but overall I'm happy with the solution (until a better one comes along).</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload