Search code examples
ruby-on-railsrubyruby-on-rails-5

Loop until there is parent_id


Need help to shorten this code.logic is until there is a parent_id in each location push the ids to _location_ids

Here is my code

     location_ids = location_id.map{|a| a.location_id}.uniq.sort #if location_id
     second_level_parent_ids = []

     location_ids.each do |loc|
         _location = Location.select(:parent_id).find(loc)
         if !_location.parent_id.nil?
             second_level_parent_ids.push(_location.parent_id)
         end
     end

     second_level_parent_ids = second_level_parent_ids.uniq.sort

     third_level_parent_ids = []
     second_level_parent_ids.each do |second_id|
         _location = Location.select(:parent_id).find(second_id)
         if !_location.parent_id.nil?
             third_level_parent_ids.push(_location.parent_id)
         end
     end

    _location_ids = location_ids + second_level_parent_ids + third_level_parent_ids

sample table fields: fields

Thank you.


Solution

  • I would try to do the heavy lifting in the database instead of loading the records into memory.

    Add this to your Location model at app/models/location.rb

    scope :with_parent_by_id, ->(ids) { where(id: ids).where.not(parent_id: nil) }
    scope :distinct_by_parent, -> { order(:parent_id).distinct }
    
    def self.uniq_present_parent_ids_for(ids)
      with_parent_by_id(idsids).distinct_by_parent.pluck(:parent_id)
    end
    

    and use it like this at the place of the example from your question

    location_ids = location_id.map(&:location_id).sort
    second_level_parent_ids = Location.uniq_present_parent_ids_for(location_ids)
    third_level_parent_ids = Location.uniq_present_parent_ids_for(second_level_parent_ids)
    
    _location_ids = (location_ids + second_level_parent_ids + third_level_parent_ids)