closure_tree icon indicating copy to clipboard operation
closure_tree copied to clipboard

How would one go about eager loading a categories collection's root categories?

Open pugsiman opened this issue 7 years ago • 1 comments

Say I have a collection of categories, how would I go about eager loading all of their root categories (unless they're the root categories themselves) in one query?

pugsiman avatar Nov 14 '18 13:11 pugsiman

(The question is 4 years, yeeeeah :penguin:)

While solving similar problem, I've ended up using association through scenic view

I have created an SQL view which looked something like this:

SELECT
    DISTINCT ON (descendant_id)
    ancestor_id AS root_id,
    descendant_id AS leaf_id,
    generations AS depth
FROM category_hierarchies
ORDER BY descendant_id, generations DESC

Then I defined a read-only model which uses this view:

# frozen_string_literal: true

class CategoryRootHierarchy < ApplicationRecord
  self.primary_key = nil

  belongs_to :leaf, class_name: 'Category'
  belongs_to :root, class_name: 'Category'

  def readonly?
    true
  end
end

... and added an association to category model:

# frozen_string_literal: true
class Category < ApplicationRecord
  has_closure_tree order: :code, name_column: :code, dependent: :destroy

  has_many :items, dependent: :nullify
  has_one :root_hierarchy, class_name: 'CategoryRootHierarchy', foreign_key: 'leaf_id', inverse_of: :leaf
end

After that I was able to preload the root category:

Item.includes(category: [{ root_hierarchy: [:root] }])

This is probably can be done on Rails level with use of ancestor_hierarchies association, but it will probably look scarier

fizvlad avatar Jun 15 '22 16:06 fizvlad