Pedigree partitions

I just completed the Railscast tutorial:

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

Is it possible to split the results from the ancestors that were organized? for example: Given that the message controller has the following:

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

Then how would I paginate the page in a way that would result in a hash?

Update I found that if I use .keys, then it will be paginated, but only the top level will not be a child.

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

Updating Each message has a code and some content. I can have attached messages

Let's pretend that

code - name

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

This is how I want to display the listing, but also want to split the pages into this sorted tree.

+4
source share
1 answer

Maybe, but I only managed to do this with two database attempts.

The main problem is the impossibility of setting restrictions for node children, which leads to truncation of node children or orphans in subsequent pages.

Example:

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

A LIMIT 0.3 (for the example above) will return the first three entries that will display everything except id: 119. Subsequent LIMIT 3.3 will return id: 119, which will not display correctly because its parents are absent.

One of the solutions I used is two queries:

  • The first returns only the root nodes. They can be sorted, and this query is paginated.
  • A second query is issued, based on the first, which returns all the children of the paginated parents. You should be able to sort children by level.

In my case, I have a Post model (which has_ancestry). Each post can have any level of answers. The post object also has a response counter, which is a cache counter for its immediate children.

In the controller:

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

In Post model:

 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 

Some notes:

  • MySQL stops using the ancestor column index if multiple LIKE statements are used. FORCE INDEX forces mySQL to use the index and prevents a full table scan.
  • LIKE statements are only created for nodes with direct children, so replies_count is useful
  • What the class method does is add the children to root, which is WillPaginate :: Collection

Finally, they can be used to control:

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

The key method is arr_nodes , which mixes with the ancestor plugin in your model as well. This basically takes a sorted array of nodes and returns a sorted and hierarchical hash.

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.

This may be a more elegant way of doing this, but overall I'm happy with the solution (until the best one comes up).

+3
source

All Articles