最新のRDBでは、再帰CTEを使用して再帰構造を処理できます。
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">]
私の知る限り、mysql、postgres、sqlite3は再帰CTEをサポートしています。
EDIT @ 2020/12/17
postgresqlでは、次のものが必要です。
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")
(指摘してくれた@Danに感謝します)