テーブル構成例
[Nodesテーブル] 最上位のノード以外は親ノードを持っている
id | name | parent_id |
---|---|---|
1 | parrent_node | null |
2 | child_node_1 | 1 |
3 | child_node_2 | 1 |
4 | child_node_1_1 | 2 |
5 | child_node_1_2 | 2 |
6 | child_node_2_1 | 3 |
7 | child_node_2_2 | 3 |
確認環境
- ruby: ruby 2.5.3
- rails: rails 5.2.2
実際のコード
class Node < ApplicationRecord
has_many :children, class_name: "Node", foreign_key: "parrent_id"
belongs_to :parrent, class_name: "Node", optional: true # rails5 から default が require になっているため `optional: true` を指定しないと `nil` での保存が不可
end
class CreateNodes < ActiveRecord::Migration[5.2]
def change
create_table :nodes do |t|
t.string :name
t.references :parrent
t.timestamps
end
end
end
実行例
テーブル構成例のデータが格納済の状態
# 最上位ノードに紐付く子ノードのレコードを取得
parrent_node = Node.first
parrent_node.children
#=> Node Load (0.8ms) SELECT `nodes`.* FROM `nodes` WHERE `nodes`.`parrent_id` = 1 LIMIT 11
#=> #<ActiveRecord::Associations::CollectionProxy [#<Node id: 2, name: "child_node_1", parrent_id: 1, created_at: "2019-02-21 09:05:38", updated_at: "2019-02-21 09:05:38">, #<Node id: 3, name: "child_node_2", parrent_id: 1, created_at: "2019-02-21 09:05:38", updated_at: "2019-02-21 09:05:38">]>
# 子ノードに紐付く親ノードのレコードを取得
child_node = Node.find(2)
child_node.parrent
#=> Node Load (0.5ms) SELECT `nodes`.* FROM `nodes` WHERE `nodes`.`id` = 1 LIMIT 1
#=> #<Node id: 1, name: "parrent_node", parrent_id: nil, created_at: "2019-02-21 09:05:37", updated_at: "2019-02-21 09:05:37">
# 最上位ノードに紐付く親ノードのレコードを取得
parrent_node = Node.first
parrent_node.parrent
#=> nil