ruby-on-railsrubyrubygemsruby-on-rails-7ruby-3

Getting all nested objects belongs to a model


I have a Location model that can have many sublocations, or one parent location. Let's say location-A is a parent location, has location-B and location-C as sublocations. But location-B also has a sublocation location-D.

How can I get all sublocations of the parent location-A, including location-D?

My model:

  has_many :sub_locations, class_name: "Location", foreign_key: "parent_location_id", inverse_of: :parent_location
  belongs_to :parent_location, optional: true, class_name: "Location", foreign_key: "parent_location_id", inverse_of: :sub_locations

Currently I fetch them like this:

  def all_sub_location_ids
    [id] + sub_locations.map(&:all_sub_location_ids).flatten
  end

But I need an efficient way. Because it throws stack level too deep

Edit: I ended up using .reload on sublocations and keep the existing method as is. This way it worked.


Solution

  • You can use gem ancestry.

    Please have a look at the official doc here

    Add Gem in your gemfile

    gem 'ancestry'
    

    Create migration

    rails g migration add_Add_ancestry_to_location ancestry:string:index
    

    In you Location model add it as below:

    class Location < ApplicationRecord
      has_ancestry
    end
    

    now you can use is as below:

    location_a = Location.create(name: 'Location A')
    location_b = Location.create(name: 'Location B', parent: location_a)
    location_c = Location.create(name: 'Location C', parent: location_a)
    location_d = Location.create(name: 'Location D', parent: location_b) 
    
    parent_location = Location.find_by(name: 'Location A')
    sublocations = parent_location.descendants
    

    here sublocations will be an array with locations as Location B, Location C, Location D.