Best Way to Handle Category/Subcategory Relationship Ruby on Rails

Best way to handle Category / Subcategory relationship Ruby on Rails

Expanding on lucapettes answer,

A nested set (https://github.com/skyeagle/nested_set) is something like this :

- category
+- category
+- category
+--- category
+- category
- category
+- category
+- category
+--- category
+- category

You can add node to the set anywhere and you would associate your product with any category.

Have a look in this file for the methods https://github.com/skyeagle/nested_set/blob/master/lib/nested_set/base.rb

The wiki for awsome_nested_set might have some better docs, https://github.com/collectiveidea/awesome_nested_set/wiki/Awesome-nested-set-cheat-sheet

For example you can move an item left, (e.g. up in a list like this ) category.move_left

To understand this model and why it works, read
Trees in SQL by Joe Celko

Rails: Association between Category, Subcategory, and Lawyer

You don't need a Subcategory model/table, specially if they have the same columns. Your categories table should have a parent_id column. A category is a subcategory when it has a parent_id value pointing to another category record. Categories with a NULL parent_id are the top level categories.

Example

class Lawyer < ActiveRecord::Base
belongs_to :category
end

class Category < ActiveRecord::Base
has_many :lawyers

# This is called a self referential relation. This is where records in a
# table may point to other records in the same table.
has_many :sub_categories, class_name: "Category", foreign_key: :parent_id

# This is a scope to load the top level categories and eager-load their
# lawyers, subcategories, and the subcategories' lawyers too.
scope :top_level, -> { where(parent_id: nil).include :lawyers, sub_categories: :lawyers }
end

Note: you should create a migration to add the parent_id column to the categories table. And you can drop the subcategories table.

Now create some of your categories (I'm assuming there's a name column):

cat = Category.create name: "Corporate and Commercial Law"
subcat = Category.new name: "Corporate Tax", parent_id: cat.id
subcat.lawyers << Lawyer.find_by_name("Sabina Mexis")
subcat.save

Example table of contents:

<% Category.top_level.each do |cat| %>
<%= cat.name %>
<% cat.sub_categories.each do |subcat| %>
<%= subcat.name %>
<%= subcat.lawyers.each do |laywer| %>
<%= lawyer.name %>
<% end %>
<% end %>
<% end %>

The above is a simplified example. Hope that helps.

Update

To enhance your form to allow you to create a subcategory and assign its parent category, use a select menu filled with top_level category IDs:

<%= form_for Category.new do |f| %>
<%= f.text_field :name %>
<%= f.select :parent_id, options_from_collection_for_select(Category.top_level, :id, :name) %>
<%= f.submit %>
<% end %>

Check out the docs for options_from_collection_for_select if it's unfamiliar. What it does is build a select menu with the category:id as values and their :name as the text in the menu. Make sure you add :parent_id to your strong parameters to allow mass assignment via params[:category].

The laywer error was just a typo in my example code, it's fixed now.

Rails active record relationship category and subcategory

That's a self join relationship, it's pure SQL, and Active Record has its way to make it work.

The line

belongs_to :parent, class_name: "Category", optional: true

is making a relationship between the categories table to itself, where the class_name is needed, because by convention Rails will use the first argument to infer the table name. The third argument optional states that there's no constraint for new records to be created with a parent_id. That strategy is what makes a category and a subcategory; categories don't have a parent_id, while subcategories must have one.

The foreign key is also inferred from the first argument parent, so the relationship is based on the column parent_id.

The second line

has_many :subcategories, class_name: "Category", foreign_key: :parent_id, dependent: :destroy

makes another relationship from categories to categories as well, but for you to have an easy way to access to subcategories having the category or vice-versa. The class_name remains the same, as it's the same table, but this time the foreign_key can not be inferred, so you must be explicit, the fourth argument dependent: :destroy is what makes every subcategory associated to a category to be destroyed when their category is destroyed, leaving no "orphan" records.

How do you get only categories and not subcategories?

Category.where(parent_id: nil)

By querying the categories table and filtering those rows with no parent_id.

How to make active record association for multiple categories and sub-categories with products/ads

You could just use one self-referential model, for example like this:

class Category < ActiveRecord::Base
has_many :child_categories, class_name: "Category", foreign_key: "parent_category_id"
belongs_to :parent_category, class_name: "Category", foreign_key: "parent_category_id"
end

Here you would use the field parent_category_id to specify the parent category when there is one. This would basically provide you with a tree structure of categories.

Then you can also easily associate ads only to this model. For example if you want to have a many to many association, you would add this to the category model:

has_and_belongs_to_many :ads

And then for the ads model:

class Ads < ActiveRecord::Base
has_and_belongs_to_many :categories
end

See also http://guides.rubyonrails.org/association_basics.html on how to set up the migrations.

As one ad can only belong to one category you can set up the associations like this:

class Category < ActiveRecord::Base
has_many :child_categories, class_name: "Category", foreign_key: "parent_category_id"
belongs_to :parent_category, class_name: "Category", foreign_key: "parent_category_id"

has_many :ads
end

class Ads < ActiveRecord::Base
belongs_to :category
end

You should also read the rails association basics guide I linked earlier. It has all relevant information and will help you to easily set up the models and associations.

How do I limit Rails 3 view to items in a specific relationship category?

Rails models have many powerful methods for various kinds of searches.

For example, if you have added

has_many :subcategories

to your Category model, your list of subcategories of a certain category should be available via:

category.subcategories

Your best bet is to have a good read of the rails guides, particularly this one and this one.

Association between category,subcategory and gig

A "belongs_to" relationship always requires a foreign key on that table.

With that being said, your gigs table should have

t.integer :user_id
t.integer :subcategory_id

and your subcategories table should have

t.integer :category_id

hope that helps!

Rails 3 Relationship between Categories, Subcategories and Items

  • Item has_one SubCategory
  • SubCategory has_one Category
  • SubCategory has_many Items
  • Category has_many SubCategories


Related Topics



Leave a reply



Submit