Skip to content


Sorting categories #10

carr opened this Issue · 10 comments

3 participants


Hello Stefan,
nice work on the ancestry gem.

I have a problem.

I have a model called "User" that has a

has_and_belongs_to_many :categories


Also, let's say I have a category tree that looks like this:

+ Node1
++ Node11
++ Node12
++ Node13
++ Node14
+ Node2
+ Node3
+ Node4
++ Node41
+++ Node411
+++ Node412
++ Node42

Now, how do I get those nodes from the database for a particular user but in the order specified above?

I tried doing

@user.categories.all(:order => 'ancestry ASC, name ASC')

But since Node1, Node2, Node3 and Node4 all have the "ancestry" field set to nil, that doesn't work.

It seems like I'm missing something, but can't put my finger on it.



Dear Tomislav,

For now you might want to check out the arrange method. (@user.categories.arrange)

I've also been thinking about other solutions to the same problem like using ancestry for eager loading. However, I don't know how to implement this yet.

Kind regards,



Hey Stefan,
actually I need this to insert into a collection_select(..) form helper so the user can choose the category.

Is there a preferred method for this, or should I try to create my own helper/patch using the "arrange" method, what do you think?



I realize this is closed, but did you ever come up with a solution for this carr? Using arrange returns a hash, but I can't seem to manipulate it using each_pair, it keeps turning it into an array.


Hello scott, no, unfortunately didn't work on this problem..


This is one method I came up with: certainly not the best way to do it, but it works:

def arranged_categories
  array =
  x = lambda { |k| 
    array << [("-" * k.depth.to_i)+ " " +,]
    if k.has_children? 

Then in the form, <%= :category_id, @categories %>


I guess you will have to cache the path of names in each node. Something like:

def before_save
  self.names_path_cache ='/')

This will save strings like 'Node4/Node41/Node411' by which you will be able to sort.

Does this work for you?

I son't see any way to sort this list in db space without an extra column.


This would work better, yes. Doing something like
Category.all.sort {|x,y| x.names_path_cache <=> y.names_path_cache }.map { |c| ["-" * c.depth +,] } produces the correct results. Thanks!


The idea of caching the names path to the db is that you can sort your list in db space:


This is obviously more performant


That is very true, I will add this to the wiki, "creating a form with ancestry", as I am sure others will find it useful, if this is ok with you!


Great! Let's close this ticket.

This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.