acts_as_nested_setを詳しく
なぜこれを?
railsにはツリー構造を表現するプラグインとして、
acts_as_treeってのとacts_as_nested_setというのがあります。
厳密にはnested_setというのはツリーとはいわないかも知れませんが、
ここでは似たようなものとして扱います。
acts_as_treeはDBの設計上、末端の検索まで時間がかかります。
これはacts_as_treeがツリーの表現としてparent_idしかないためです。
簡単な組織ならいいのですが、組織が入れ子になって200とかある
組織だと組織図を作るだけでonzの状態です。時間がかかります。
数が多い場合はnested setを使いましょう。
まず準備
migrationファイルに以下のように書きます。parent_id、lft、rgtは必須。
create_table :sections do |t| t.column :parent_id, :integer t.column :lft, :integer t.column :rgt, :integer t.column :name, :string end
カラム名を変えたい場合はoptionsで指定します。:parent_column、:left_column、right_columnが使えます。:scopeは今回は紹介を省略します。
class Section < ActiveRecord::Base acts_as_nested_set :options=>{:order=>"id"} end
使ってみる
データを入力するのが面倒なのでmigrateに全部書いてみます。
def self.up create_table :sections do |t| t.column :parent_id, :integer t.column :lft, :integer t.column :rgt, :integer t.column :name, :string end Section.new(:name=>"福島本社").save! # 0 Section.new(:name=>"営業部").save! # 1 Section.new(:name=>"営業課").save! Section.new(:name=>"第一営業係").save! Section.new(:name=>"第二営業係").save! Section.new(:name=>"企画課").save! Section.new(:name=>"第一企画係").save! Section.new(:name=>"第二企画係").save! Section.new(:name=>"経理部").save! # 8 Section.new(:name=>"会計課").save! Section.new(:name=>"第一会計係").save! Section.new(:name=>"第二会計係").save! Section.new(:name=>"契約課").save! Section.new(:name=>"第一契約係").save! Section.new(:name=>"第二契約係").save! Section.new(:name=>"第三契約係").save! Section.new(:name=>"総務部").save! # 16 Section.new(:name=>"人事課").save! Section.new(:name=>"人事係").save! Section.new(:name=>"総務課").save! Section.new(:name=>"第一総務係").save! Section.new(:name=>"第二総務係").save! Section.new(:name=>"第三総務係").save! Section.new(:name=>"広報課").save! Section.new(:name=>"広報係").save! Section.new(:name=>"仙台支社").save! # 25 Section.new(:name=>"東京支社").save! sections=Section.find(:all) sections[0].add_child(sections[1]) sections[1].add_child(sections[2]) sections[2].add_child(sections[3]) sections[2].add_child(sections[4]) sections[1].add_child(sections[5]) sections[5].add_child(sections[6]) sections[5].add_child(sections[7]) sections[0].add_child(sections[8]) sections[8].add_child(sections[9]) sections[9].add_child(sections[10]) sections[9].add_child(sections[11]) sections[8].add_child(sections[12]) sections[12].add_child(sections[13]) sections[12].add_child(sections[14]) sections[12].add_child(sections[15]) sections[0].add_child(sections[16]) sections[16].add_child(sections[17]) sections[17].add_child(sections[18]) sections[16].add_child(sections[19]) sections[19].add_child(sections[20]) sections[19].add_child(sections[21]) sections[19].add_child(sections[22]) sections[16].add_child(sections[23]) sections[23].add_child(sections[24]) end
この状態でツリー表現になっています。
インスタンスメソッド一覧
- root?
自分がツリーのトップかどうか
- child?
自分がどこかにぶら下がっているかどうか?
- unknown?
自分が迷子かどうか?(親も子もない場合)
- add_child(child)
自分に子をぶら下げる
- children_count
自分にぶら下がっている子の総数を返す
- full_set
自分とぶら下がっている子全てを配列で返す
- all_children
自分にぶら下がっている子全てを配列で返す
- direct_children
自分の直接ぶら下がっている子を配列で返す
- before_destroy
どういう場合に使うのかよくわかりません。あまり使わない方がよさそうです。