Retrieve all parents, all possible children, sorted and with their "depth" I have a model section with a column parent_id - the only thing identifying a parent/child relationship. I wrote a helper method to output all sections, all their possible subsections and include their "depth".

This is the helper method:

# Calls itself for each section recursively to fetch all possible children
def fetch_all_sections(standard, section = nil, depth = 0)
  all_sections = []
  if section.nil?
    rootsections = roots(standard.sections.sorted)
    if ! rootsections.nil?
      rootsections.each do |section|
        all_sections.push(fetch_all_sections(standard, section))
      end
    end
  else
    all_sections.push({:id =&gt; section.id, :sortlabel =&gt; section.sortlabel, :title =&gt; section.title, :depth =&gt; depth})
    section.children.sorted.each_with_index do |section, index|
      all_sections.push(fetch_all_sections(standard, section, (depth += 1) - index))
    end
  end
  return all_sections
end


sorted is a module method which sorts based on the sort_key column using regular expressions. The output of debug(fetch_all_sections(@standard)) is:

- - "1 Collaborase Test Document depth: 0"
  - - "1.1 Section One Dot One depth: 1"
  - - "1.a Testing 123 depth: 1"
  - - "1.b Section One dot B depth: 1"
    - - "1.b.1 Testing One B One depth: 2"
- - "2 Identify Project GHG Sources, Sinks, and Reservoirs (SSRs) depth: 0"
  - - "2.a Section Two dot A depth: 1"
- - "3 Identify the Baseline depth: 0"
- - "4 Identify the Baseline GHGs depth: 0"
- - "5 Identify SSRs Relevant for Quantification depth: 0"
  - - "5.1 Section Five Dot One depth: 1"
- - "6 GHG Quantification depth: 0"
- - "7 Monitoring depth: 0"
- - "8 Data and Information Retention depth: 0"
- - "9 QA/QC depth: 0"


My questions is this:

In this loop:

&lt;% fetch_all_sections(@standard).each do |section| %&gt;
  &lt;%= debug section %&gt;
&lt;% end %&gt;


I want each section and all their children to be separated. Instead, each section in the above loop contains their children.

Instead of this:



--- 
- - :id: 122
    :sortlabel: "5"
    :title: Identify SSRs Relevant for Quantification
    :depth: 0
- - - :id: 412
      :sortlabel: "5.1"
      :title: Section Five Dot One
      :depth: 1


I want this:

--- 
- - :id: 122
    :sortlabel: "5"
    :title: Identify SSRs Relevant for Quantification
    :depth: 0
---
- - :id: 412
    :sortlabel: "5.1"
    :title: Section Five Dot One
      :depth: 1
What I needed was the pipe operator! It was of course just doing what I was telling it to - pushing the results of itself onto the current element in the array. Only when the rootsections loop completes does it start a new array element.

The 'pipe' (|) is a different array merge operator which appends what's to the right of it onto the end of the array on the left.

all_sections | fetch_all_sections(standard, section, depth)


The pipe operator changed how depth worked so instead I just counted the number of "." in sortlabel:

depth = section.sortlabel.split('.').length -1


The full method:

# Calls itself for each section recursively to fetch all possible children
def fetch_all_sections(standard, section = nil, depth = 0)
  all_sections = []

  if section.nil?
    rootsections = standard.sections.sorted
    if ! rootsections.nil?
      rootsections.each_with_index do |section, i|
        depth = section.sortlabel.split('.').length - 1
        all_sections &lt;&lt; fetch_all_sections(standard, section, depth).first
      end
    end
  else

    all_sections &lt;&lt; {:id =&gt; section.id, :sortlabel =&gt; section.sortlabel, :title =&gt; section.title, :depth =&gt; depth}

    section.children.sorted.each do |section|
      all_sections | fetch_all_sections(standard, section)
    end
  end

  return all_sections
end


If someone seeing this is considering something similar but starting from scratch, consider an Active Record Nesting gem: https://www.ruby-toolbox.com/categories/Active_Record_Nesting

UPDATE: I added .first within the rootsections loop. This is because I inadvertently built an array of arrays, each containing 1 hash. What I wanted was an array of hashes. Much easier retrieval now!