eldi
eldi

Reputation: 1259

self join how to reference the association from parent

I have Category class shown below

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

  belongs_to :main_category
end

and I wonder if I can define main_category association the rails way that I can reference the #main_category on subcategories but leaving the main_category_id empty (as the reference on subcategory#main_category_id will duplicate the data which is in parent_category#main_category_id or it is just premature optimization?😅 ).

category = Category.new main_category: main_category
subcategory = Category.new parent_category: category

assert_equal category.main_category, subcategory.main_category

Upvotes: 0

Views: 58

Answers (2)

max
max

Reputation: 101976

You can use indirect assocations to setup "short-cuts" through the tree.

class Category < ActiveRecord::Base

  # Going up...
  has_many :subcategories, 
     class_name: "Category", 
     foreign_key: "parent_category_id"
  has_many :grand_child_categories, 
     class_name: "Category", 
     through: :subcategories
  has_many :great_grand_child_categories, 
     class_name: "Category", 
     through: :grand_child_categories

  # Going down...
  belongs_to :parent_category, 
    class_name: "Category"
  has_one :grand_parent_category, 
    through: :parent_category,
    class_name: "Category"
  has_one :great_grand_parent_category, 
    through: :grand_parent_category,
    class_name: "Category"
end

However if you have a heirarchy of unlimited depth ActiveRecord::Assocations can't really solve the problem of finding the node at the bottom of the tree. That requires more advanced SQL like a recursive common table expression (CTE).

While ActiveRecord does has the basic tools for creating self joining assocations most of the more andvaced stuff is out of scope and can be handled with gems like Ancestry.

Upvotes: 1

Lam Phan
Lam Phan

Reputation: 3811

you can create a proxy that subcategories will delegate main_category to parent, the drawback that there're 3 queries to get main_category

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

 belongs_to :main_category, class_name: "Category"

 # with subcategories, there're 3 queries: 
 # super return nil -> find parent_category -> find main_category of the parent 
 def main_category
   super || parent_category&.main_category
 end
end

Upvotes: 1

Related Questions