Listing category-subcategory relationship upto nth level

I have a categories table in which one parent_id column is there, following is the Category model

class Category < ActiveRecord::Base

  has_many :subcategories, :class_name => "Category", :foreign_key => :parent_id, :dependent => :destroy
  has_one :parent, :class_name => "Category", :primary_key => :parent_id, :foreign_key => :id
end

I want to show the parent child heirarchy which is totally dynamic, it can extend upto nth level. How to show it on a page using unordered list. Currently I am showing upto 3 level, but I want make it dynamic. Currently I'm using this to show it upto 3 levels, but this method is not feasible beacuse it can extend to more than 3 levels.

<% @categories.each do |category| %>
        <ul>
          <% if category.parent_id.blank? %>
            <li class="big-bold"><%= category.name %> <%= link_to "Edit", edit_admin_category_path(category), :class => "btn btn-primary btn-xs" %> <%= link_to "Delete", admin_category_path(category), :method => 'delete', :class => "btn btn-danger btn-xs", data: { confirm: 'Are you sure?' } %>
              <% if category.subcategories.present? %>
                <ul>
                  <% category.subcategories.each do |sub| %>
                    <li class="top-clear"><%= sub.name %> <%= link_to "Edit", edit_admin_category_path(sub), :class => "btn btn-primary btn-xs" %> <%= link_to "Delete", admin_category_path(sub), :method => 'delete', :class => "btn btn-danger btn-xs", data: { confirm: 'Are you sure?' } %>
                      <% if sub.subcategories.present? %>
                        <ul>
                          <% sub.subcategories.each do |subtwo| %>
                            <li class="top-clear"><%= subtwo.name %> <%= link_to "Edit", edit_admin_category_path(subtwo), :class => "btn btn-primary btn-xs" %> <%= link_to "Delete", admin_category_path(subtwo), :method => 'delete', :class => "btn btn-danger btn-xs", data: { confirm: 'Are you sure?' } %></li>
                          <% end %>
                        </ul>
                      <% end %>

                    </li>
                  <% end %>
                </ul>
              <% end %>
            </li>
          <% end %>
        </ul>
  <% end %>

logs of database queries

Started GET "/admin/categories" for 127.0.0.1 at 2014-02-27 12:13:10 +0530
Processing by Admin::CategoriesController#index as HTML
  User Load (0.2ms)  SELECT `users`.* FROM `users` WHERE `users`.`id` = 14 ORDER BY `users`.`id` ASC LIMIT 1
  UserType Load (0.2ms)  SELECT `user_types`.* FROM `user_types` WHERE `user_types`.`id` = 3 ORDER BY `user_types`.`id` ASC LIMIT 1
  Category Load (0.3ms)  SELECT id, name, parent_id, slug FROM `categories`
  Category Load (0.3ms)  SELECT `categories`.* FROM `categories` WHERE `categories`.`parent_id` IN (8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 33, 34)
  Category Load (0.2ms)  SELECT `categories`.* FROM `categories` WHERE `categories`.`parent_id` = 9
  Category Load (0.2ms)  SELECT `categories`.* FROM `categories` WHERE `categories`.`parent_id` = 10
  Category Load (0.6ms)  SELECT `categories`.* FROM `categories` WHERE `categories`.`parent_id` = 11
  Category Load (0.2ms)  SELECT `categories`.* FROM `categories` WHERE `categories`.`parent_id` = 12
  Category Load (0.2ms)  SELECT `categories`.* FROM `categories` WHERE `categories`.`parent_id` = 13
  Category Load (0.2ms)  SELECT `categories`.* FROM `categories` WHERE `categories`.`parent_id` = 14
  Category Load (0.2ms)  SELECT `categories`.* FROM `categories` WHERE `categories`.`parent_id` = 15
  Rendered admin/categories/_subcategory.html.erb (92.5ms)
  Category Load (0.2ms)  SELECT `categories`.* FROM `categories` WHERE `categories`.`parent_id` = 17
  Category Load (0.2ms)  SELECT `categories`.* FROM `categories` WHERE `categories`.`parent_id` = 18
  Category Load (0.2ms)  SELECT `categories`.* FROM `categories` WHERE `categories`.`parent_id` = 19
  Category Load (0.2ms)  SELECT `categories`.* FROM `categories` WHERE `categories`.`parent_id` = 20
  Category Load (0.2ms)  SELECT `categories`.* FROM `categories` WHERE `categories`.`parent_id` = 21
  Rendered admin/categories/_subcategory.html.erb (7.9ms)
  Category Load (0.2ms)  SELECT `categories`.* FROM `categories` WHERE `categories`.`parent_id` = 24
  Category Load (0.2ms)  SELECT `categories`.* FROM `categories` WHERE `categories`.`parent_id` = 25
  Category Load (0.2ms)  SELECT `categories`.* FROM `categories` WHERE `categories`.`parent_id` = 26
  Category Load (0.2ms)  SELECT `categories`.* FROM `categories` WHERE `categories`.`parent_id` = 27
  Rendered admin/categories/_subcategory.html.erb (5.9ms)
  Category Load (0.2ms)  SELECT `categories`.* FROM `categories` WHERE `categories`.`parent_id` = 28
  Category Load (0.2ms)  SELECT `categories`.* FROM `categories` WHERE `categories`.`parent_id` = 29
  Category Load (0.2ms)  SELECT `categories`.* FROM `categories` WHERE `categories`.`parent_id` = 30
  Category Load (0.2ms)  SELECT `categories`.* FROM `categories` WHERE `categories`.`parent_id` = 33
  Rendered admin/categories/_subcategory.html.erb (8.3ms)
  Rendered admin/categories/index.html.erb within layouts/admin (129.8ms)
  Rendered layouts/admin/_header.html.erb (2.0ms)
  Rendered layouts/admin/_flash_messages.html.erb (0.1ms)
Completed 200 OK in 159ms (Views: 142.3ms | ActiveRecord: 4.9ms)

Answers


You can make a partial that contains the recurrent markup, i.e., something like this:

<% @categories.each do |category| %>
        <ul>
          <% if category.parent_id.blank? %>
            <li class="big-bold"><%= category.name %> <%= link_to "Edit", edit_admin_category_path(category), :class => "btn btn-primary btn-xs" %> <%= link_to "Delete", admin_category_path(category), :method => 'delete', :class => "btn btn-danger btn-xs", data: { confirm: 'Are you sure?' } %>
              <% if category.subcategories.present? %>
                <%= render partial: 'subcategory', locals: {subcategories: category.subcategories} %>
              <% end %>
                </ul>
              <% end %>
            </li>
          <% end %>
        </ul>
  <% end %>

and make subcategory partial look like this:

<ul>
  <% subcategories.each do |sub| %>
    <li class="top-clear"><%= sub.name %> <%= link_to "Edit", edit_admin_category_path(sub), :class => "btn btn-primary btn-xs" %> <%= link_to "Delete", admin_category_path(sub), :method => 'delete', :class => "btn btn-danger btn-xs", data: { confirm: 'Are you sure?' } %>
  <% if sub.subcategories.present? %>
    <%= render partial: 'subcategory', locals: {subcategories: sub.subcategories} %>
  <% end %>

</li>
  <% end %>
</ul>

Need Your Help

Set onItemClick to Custom adapter ListView

java android listview android-listview

When I had problems trying to fix the position of my listView items to the desired intent when filtered, and got info I could override the problem using a custom adapter, I have done that but I do ...

How to configure the ruby edition on rails

ruby-on-rails ruby

I am using MAC to learn RoR. The default Ruby in system is 2.0.0, and I installed the newest Ruby 2.2.1(not in System). However, when I run rails server, it uses ruby 2.0.0. How can I configure rai...

About UNIX Resources Network

Original, collect and organize Developers related documents, information and materials, contains jQuery, Html, CSS, MySQL, .NET, ASP.NET, SQL, objective-c, iPhone, Ruby on Rails, C, SQL Server, Ruby, Arrays, Regex, ASP.NET MVC, WPF, XML, Ajax, DataBase, and so on.