user3543006
user3543006

Reputation: 83

How do you create a model with categories that has subcategories (using Rails)?

I am creating a blog through Rails. I am relating the posts and categories models through a many-to-many relationship. How do I incorporate subcategories in this model?

Upvotes: 2

Views: 1566

Answers (2)

Richard Peck
Richard Peck

Reputation: 76784

Hierarchy

The best way is to use one of the hierarchy gems, typically Ancestry or Closure_Tree to create a "tree" type structure for your categories. You'll then be able to associate blogs with each category, creating the hierarchy functionality you need.

We've achieved this before - using the Ancestry gem:


Categories

enter image description here

As you can see from the above image, the "secret sauce" you're missing is that your categories are not in a hierarchy-based structure.

The reason this is important is because if you associate your blog posts with specific categories, in order for those categories to achieve the "sub category" structure you desire, you need to be able to create a system which supports it, hence the hierarchy gems.

Specifically, you're currently working on creating a separate sub_category.rb model. The right way to do it is to keep it with one model - Category - and use the hierarchy gems to provide you with the tree infrastructure.

Here's how we do it:

#app/models/category.rb
class Category < ActiveRecord::Base
   has_ancestry #-> enables the "ancestry" gem
   has_and_belongs_to_many :posts
end

#app/models/post.rb
class Post < ActiveRecord::Base
   has_and_belongs_to_many :categories #-> you'll need a blogs_categories table with blog_id | category_id
end

Controller

The important thing to note from your perspective is that you will need to ensure you have the right "controller actions" in place, to assign the correct category to your blog:

#app/controllers/posts_controller.rb
class PostsController < ApplicationController 
   def new
      @post = Post.new
   end

   def create
      @post = Post.new post_params
      @post.save
   end

    private

    def post_params
       params.require(:post).permit(:title, :body, :category_ids)
    end
end

View

Finally, the real magic of this setup is that if you want to display your items in a hierachy / tree format, you'll be able to use the Ancestry association methods to give you the ability to create "nested" lists:

enter image description here

To do this, you'll just need to use a partial, which will call the children of the parent objects, allowing you to show a "tree" type hierarchy (as well as creating subcategories):

#app/views/categories/_category.html.erb
<ol class="categories">
    <% collection.arrange.each do |category, sub_item| %>
        <li>
            <!-- Category -->
            <%= link_to category.title, edit_admin_category_path(category) %>

            <!-- Children -->
            <% if category.has_children? %>
                <%= render partial: "category", locals: { collection: category.children } %>
            <% end %>

        </li>
    <% end %>
</ol>

This will allow you to call the following:

#app/views/categories/index.html.erb
<%= render partial: "category", locals: { collection: @categories } %>

Upvotes: 4

dav1dhunt
dav1dhunt

Reputation: 179

Create a sub_categories model, like so:

# post.rb
has_and_belongs_to_many :categories
has_many :sub_categories

# category.rb
has_and_belongs_to_many :posts
has_many :sub_categories


# sub_category.rb
belongs_to :category
belongs_to :post
# delegate attributes like so
delegate: :title, to: :category

Read more about them in the rails guide

Upvotes: 0

Related Questions