Matt Elhotiby
Matt Elhotiby

Reputation: 44066

How would I sort and group this and loop over it with rails?

Ok so i have a pages table with all the static with this schema

create_table "pages", :force => true do |t|
  t.string   "name"
  t.text     "html"
  t.string   "url"
  t.integer  "position"
  t.boolean  "is_home"
  t.integer  "parent_id",  :default => 0, :null => false
  t.string   "nav"
end

A page can have another page as its parent. The idea is that I want the user to have complete control of the navigation and the pages. So my question what is the best way to group these pages so in the html i can loop over all the pages and their subpages

Here is what i have so far

grouped_pages = Page.where(:is_home => 0).group_by(&:nav).each do |key, group|
 group.sort_by(&:parent_id)
end

I was hoping to group them in some array and or hash combination with another layer for ever page that has a parent_id of another page

the page structure can look like this

Page1
  Page3
    Page7
  Page4
  Page5
Page2
  Page5
  Page6

Any ideas of the best way to sort and loop over to print out the uls for the html

Upvotes: 1

Views: 571

Answers (2)

rewritten
rewritten

Reputation: 16435

With a gem like closure tree you can have the same basic tree behavior, plus all the following:

  • a nested hash with all the hierarchy
  • the list of all ancestors of a node
  • all descendants of a node
  • all the siblings of a node

and many others, implemented so to execute only one query.

(See http://matthew.mceachen.us/blog/tags/closure-tree for reasons behind such a tree.)

Upvotes: 1

tokland
tokland

Reputation: 67880

If you want to allow arbitrarily nested tree levels, the easiest solution is a recursive algorithm. For example (uses parent_id = NULL, not 0, for the page root):

class Page < ActiveRecord::Base
  belongs_to :parent, :class_name => :Page
  has_many :children, :class_name => :Page, :foreign_key => :parent_id 

  def self.root
    where(:parent => nil).first
  end

  def tree
    [self, children.map(&:tree)]
  end
end

Page.root.tree 
#=> returns the structure in pairs [page, children]

From this you can do whatever you need. For exemple, to set a sort criterion, just add an options argument to tree and use it to scope children.

Note that to render a tree structure you also need a recursive helper to perform the task. In fact probably you don't need this tree method, just a recursive helper that calls children, but the idea is the same.

As Mark points out, there are gems to implement AR trees, for example acts_as_tree.

Upvotes: 3

Related Questions