Joshua
Joshua

Reputation: 83

How to group 'each do' output by parent?

I am currently using the acts_as_tree gem and wish to display all my category names, separated by parent category names. Here is what I have tried.

<% @categories.each do |category| %>
<h4><%= category.parent.name if category.parent %></h4>
<%= category.name%>
<% end %>

It doesn't work because the parent titles are being repeated for every child. What I wish to achieve is parents only displayed once, followed by its children as such.

Parent 1

Parent 2

Any help is appreciated!

Upvotes: 0

Views: 1214

Answers (4)

sreang rathanak
sreang rathanak

Reputation: 542

Here what I come with.

<% @categories.roots.each do |parent| %>
  <h4><%= category.parent.name %></h4>
  <% parent.children.each do |child| %>
    <%= parent.name %> <%= child.name%>
  <% end %>
<% end %>

However, this work for 1 level categories only. If you want deep level categories, you may need to define a recursive method for that.

Upvotes: 0

Jeremie
Jeremie

Reputation: 2411

I think you could accomplish something like :

<% parents.each do |parent| %>
  <h4><%= parent.name %></h4>
  <% parent.children.each do |child| %>
    <%= child.name %>
  <% end %>
<% end %>

So for your example :

<% @categories.parents.each do |parent| %>
  <h4><%= parent.name %></h4>
  <% parent.children.each do |category| %>
    <%= category.name %>
  <% end %>
<% end %>

Depending on the name of the parent of your category model, you could also do :

Parent.tree_view(:name)

Upvotes: 1

sonna
sonna

Reputation: 620

You can first group categories together by the parent they have in common, using the group_by method for enumerables; e.g.

@categories.group_by(&:parent)

It will produce a Hash something like the following:

# { 
#   parent1 => [category1, category2],
#   parent2 => [category3]
# }

# or

{#<Parent:0x007fa92582f930 @name="Parent1">=>
  [#<Category:0x007fa92582f868
    @name="Category1",
    @parent=#<Parent:0x007fa92582f930 @name="Parent1">>,
   #<Category:0x007fa92582f7c8
    @name="Category2",
    @parent=#<Parent:0x007fa92582f930 @name="Parent1">>],
 #<Parent:0x007fa92582f8b8 @name="Parent1">=>
  [#<Category:0x007fa92582f750
    @name="Category3",
    @parent=#<Parent:0x007fa92582f8b8 @name="Parent1">>]}

And with that you iterate over each Parent and its grouped Categories to render in your view template like so:

<% @categories.group_by(&:parent).each do |parent, categories| %>
  <h4><%= parent.name if parent %></h4>
  <% categories.each do |category| %>
    <%= category.name %>
  <% end %>
<% end %>

Upvotes: 1

eonu
eonu

Reputation: 71

What exactly is category.parent? If it isn't nil or explicitly false, then <h4><%= category.parent.name if category.parent %></h4> will always display category.parent.name, because the if statement is essential checking whether category.parent exists. And assuming a parent exists for each child, it will display the parent each time. You'll have to change the if statement.

Sorry I couldn't be of more help, perhaps I could give a suggestion if you edit the post to include the code from category or parent.

Upvotes: 0

Related Questions