how to make a Recursive function in rails,that will return all CHILDREN of a parent,and children of all CHILDREN AND SO ON....TO N-LEVELS

Viewed 6815

I have a method as shown:

def all_pages_and_its_n_level_child

     @parent_pages = Page.where(:parent_id => params[:page_id])
     #this will give me all child of this page
     for page in @parent_pages
          child_exists=Page.where(:parent_id=>page.id)
          #this will give all children of that page
          #*I want to make this loop further so that i can check to N-levels,
          #this is only for two levels*
     end


end  
3 Answers

On modern RDBs, recursive CTE can be used to handle recursive structure.

class Page < ApplicationRecord; end

Page.find_by_sql(
  "WITH RECURSIVE r AS (
     #{Page.where(id: 2).to_sql}
     UNION ALL
     #{Page.joins('JOIN r').where('r.id = pages.parent_id').to_sql})
   SELECT * FROM r")

#  Page Load (0.7ms)  WITH RECURSIVE r AS (
#     SELECT `pages`.* FROM `pages` WHERE `pages`.`id` = 2
#     UNION ALL
#     SELECT `pages`.* FROM `pages` JOIN r WHERE (r.id = pages.parent_id))                                                              
#   SELECT * FROM r
#    => [#<Page id: 2, parent_id: 1, created_at: "2018-08-21 15:00:43", updated_at: "2018-08-21 15:00:43">, #<Page id: 3, parent_id: 2, created_at: "2018-08-21 15:00:50", updated_at: "2018-08-21 15:00:50">]

As far as I know, mysql, postgres, sqlite3 supports recursive CTE.


EDIT@2020/12/17

On postgresql, you need to have following:

Page.find_by_sql(
  "WITH RECURSIVE r AS (
     #{Page.where(id: 2).to_sql}
   UNION ALL
     #{Page.joins('JOIN r ON r.id = pages.parent_id').to_sql})
   SELECT * FROM r")

(Thanks to @Dan for pointing out)

Related