Rails: Tree concern の習作
下記の投稿で紹介されていた Tree concern を用いた木構造(ツリー構造)を実装してみました。
リポジトリ:
アプリの作成
習作用のアプリを作成します。
rails new study_tree_concern
cd study_tree_concern
Pin モデルを生成します。
区別しやすいように string 型 name を持たせます。
記事では名前空間を持つ Bucket::Pin ですが今回の習作では Pin にします。
ジェネレータのコマンドに自テーブルを参照するオプションは無いようですので後から追加します。
bin/rails g model Pin name
code . db/migrate/*_create_pins.rb
外部キーを追加します。
t.references :parent, foreign_key: { to_table: :pins }
class CreatePins < ActiveRecord::Migration[7.0]
def change
create_table :pins do |t|
t.string :name
t.references :parent, foreign_key: { to_table: :pins }
t.timestamps
end
end
end
マイグレートします。
bin/rails db:migrate
Tree concern を作成して、Pin モデルに include します。
code app/models/concerns/tree.rb
module Tree
extend ActiveSupport::Concern
included do |base|
belongs_to :parent, class_name: base.to_s, touch: true, optional: true, inverse_of: :children
has_many :children, class_name: base.to_s, foreign_key: :parent_id, dependent: :destroy, inverse_of: :parent
scope :roots, -> { where(parent: nil) }
scope :children_of, ->(parent) { where(parent: parent) }
end
def adopt(children)
transaction do
Array(children).each do |child|
child.update! parent: self
end
end
end
end
code app/models/pin.rb
class Pin < ApplicationRecord
include Tree
end
動作確認
次のモデルを作って動作確認します。
参考:Mermaidのコード
classDiagram
a1 --> b11
a1 --> b12
b12 --> C123
a2 --> b21
コンソールで動作確認します。
bin/rails c -s
木構造のモデルを作成します。
a1 = Pin.create! name: "a1"
b11 = Pin.create! name: "b11"
b12 = Pin.create! name: "b12"
c121 = Pin.create! name: "c121"
a1.adopt [b11, b12]
b12.adopt c121
a2 = Pin.create! name: "a2"
a2.adopt Pin.create! name: "b21"
動作確認します。
a1.children # => [b11, b12]
b11.parent # => a1
b12.children # => [c121]
c121.parent # => b12
Pin.roots # => [a1, a2]
Pin.children_of a1 # => [b11, b12]
Pin.children_of b11 # => []
Pin.children_of b12 # => [c121]
Pin.children_of c121 # => []
以上です。
この記事が気に入ったらサポートをしてみませんか?