3
\$\begingroup\$

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 => section.id, :sortlabel => section.sortlabel, :title => section.title, :depth => 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:

<% fetch_all_sections(@standard).each do |section| %>
  <%= debug section %>
<% end %>

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
\$\endgroup\$
2
  • \$\begingroup\$ Derp. The syntax is all_sections.push([section.sortlabel, section.title, depth]). I'll leave the question open to see if anyone comes up with something better. \$\endgroup\$
    – Archonic
    Commented Jan 16, 2013 at 19:38
  • \$\begingroup\$ I opted for pushing keys for easier retrieval: all_sections.push({:id => section.id, :sortlabel => section.sortlabel, :title => section.title, :depth => depth}) \$\endgroup\$
    – Archonic
    Commented Jan 16, 2013 at 20:39

1 Answer 1

1
\$\begingroup\$

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 << fetch_all_sections(standard, section, depth).first
      end
    end
  else

    all_sections << {:id => section.id, :sortlabel => section.sortlabel, :title => section.title, :depth => 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!

\$\endgroup\$
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.