Reputation: 1259
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
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
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