Retrieve all parents, all possible children, sorted and with their "depth"
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!