4

Using awesome_nested_set with Rails 3, I've created a hierarchical categories system. To display the category selector in the view, I've used the following code:

<%= form.select :parent_id, options_for_select(nested_set_options(Category, @category) {|i| "#{'-' * i.level} #{i.name}" }.unshift(["No Parent", nil]), @category.parent_id) %>

I'm attempting to order the categories in alphabetical order, on a level by level basis. If I change the nested_set_options(Category, @category) to nested_set_options(Category.order("name"), @category) this will reorder the whole categories list by name; what I want to do is reorder the children of each node alphabetically by name.

For example, I want to resulting select menu to be ordered like this:

Animal
- Bird
-- Chicken
-- Hawk
- Fish
-- Cod
-- Goldfish
-- Trout
- Mammal
-- Cat
-- Primate
--- Chimpanzee
--- Human
-- Zebra
Plant
- Tree
Chris Alley
  • 3,015
  • 2
  • 21
  • 31

3 Answers3

2

Although I am unfamiliar with awesome_nested_set, you can call order twice in Rails 3.

Category.order(:level).order(:name)

This should order Category by each level and then by name within each level. Also, you can throw this on the default scope within the model.

class Category < ActiveRecord::Base
  default_scope order('level, name')
  ...
end

Orders are great for default scope because they don't effect any default values.

awilkening
  • 1,062
  • 8
  • 26
  • Since this post, we have realized the difficulty in using order in the default scope when dealing with data manipulation. – awilkening Oct 31 '11 at 19:13
  • Two points on this solution: (1) in awesome_nested_set the default "level" descriptor is called :depth. (2) this will lose the hierarchy. i.e. it will list all the level-2 categories (alphabetized), then all the level-3s (alphabetized), instead of listing the level-3's below their parent level-2 category, which is what the OP wanted. – Nick Gobin Jun 20 '23 at 18:27
1

You can use @item.children.except(:order).order("your_sort_column") as suggested in this stackoverflow post: awesome nested set order by

Community
  • 1
  • 1
Morgan Christiansson
  • 29,280
  • 1
  • 19
  • 13
  • Actually, another answer there handles this better. Just doing and order alphabetizes everything and loses the heirarchical structure. It's unfortunate there's not an easy way to do this yet other than the below, which hits the database N times. https://stackoverflow.com/a/32238180/16952511 – Nick Gobin Jun 20 '23 at 18:24
0

I had the same issue. I solved it as described here. Basically adding the below method to the model that acts_as_nested_set allows you to return a flat array of objects for the select tag in the view by calling @category.sorted_heir_list:

  def sorted_heir_list(target = self, set = self.descendants)
    sorted_list = [target]
    kids = set.select{|i| i.parent_id == target.id}.sort_by{|j| j.name}
    kids.each do |k|
      sorted_list.concat(sorted_heir_list(k, set))
    end
    sorted_list
  end

I like this method better than the other answer that I linked in my comment on Morgan Christiansson's answer because it only incurs a single DB hit (vs. N hits with the other approach).

Nick Gobin
  • 131
  • 13