Chris Alley
Chris Alley

Reputation: 3035

Ordering category select menu alphabetically with awesome_nested_set

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

Upvotes: 4

Views: 1715

Answers (3)

NGobin
NGobin

Reputation: 403

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).

Upvotes: 0

Morgan Christiansson
Morgan Christiansson

Reputation: 29450

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

Upvotes: 1

awilkening
awilkening

Reputation: 1062

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.

Upvotes: 2

Related Questions