イケテル
better nested set
      研究会
   藤岡岳之(xibbar)
アジェンダ




better nested setを使って組織図を書く
手軽に書きたいんだ∼!
Sectionモデルを作成1




better nested setをインストール
Sectionモデルを作成2
migrationファイル
  モデルはSectionという名前にすることにして、使用
  するカラムはnameだけに
  better nested setにはparent_id、lft、rgtとい
  う:integerなカラムが必要
class CreateSections < ActiveRecord::Migration
 def self.up
   create_table :sections do ¦t¦
    t.column :name, :string, :null=>false
    t.column :parent_id, :integer
    t.column :lft,    :integer
    t.column :rgt,      :integer
   end
 end
 def self.down
   drop_table :sections
 end
end
Sectionモデルを作成3

app/models/section.rbの中身


   class Section < ActiveRecord::Base
           acts_as_nested_set
   end
データを作成

              ツリーを作成してみる
%   ./script/runner   'Section.create(:name=>"日本Ruby会議")'
%   ./script/runner   'Section.create(:name=>"東京Ruby会議").move_to_child_of Section.find_by_name("日本Ruby会議")'
%   ./script/runner   'Section.create(:name=>"札幌Ruby会議").move_to_child_of Section.find_by_name("日本Ruby会議")'
%   ./script/runner   'Section.create(:name=>"Akasaka.rb").move_to_child_of Section.find_by_name("東京Ruby会議")'
%   ./script/runner   'Section.create(:name=>"Asakusa.rb").move_to_child_of Section.find_by_name("東京Ruby会議")'




              DBの中身は
                             # select * from sections;
                              id ¦   name       ¦ parent_id ¦ lft ¦ rgt
                             ----+--------------+-----------+-----+-----
                               1 ¦ 日本Ruby会議 ¦                ¦ 1 ¦ 10
                               2 ¦ 東京Ruby会議 ¦              1¦ 2¦ 7
                               3 ¦ 札幌Ruby会議 ¦              1¦ 8¦ 9
                               4 ¦ Akasaka.rb ¦            2¦ 3¦ 4
                               5 ¦ Asakusa.rb ¦            2¦ 5¦ 6
                             (5 rows)
自作プラグインを導入



./script/plugin install http://xibbar.net/svn/
rails/plugins/trunk/acts_as_section_map/
モデルに一行追加


     class Section < ActiveRecord::Base
      acts_as_nested_set
      acts_as_section_map
     end


※ acts_as_section_mapは
  acts_as_nested_setの下に書くこと
コントローラー
                1行追加

class WelcomeController <ApplicationController
 def index
  @table2=Section.table2
 end
end
ビュー
index.rhtml
 <% section_map(@table2) do ¦table¦ %>
  <%=table.name%>
 <% end %>
   ※ テーブルの中身はブロックで指定




    ※ プラグインの魔法で、
    たったこれだけで組織図完成
関連テーブル
    user.rb                                       section.rb
                                              class Section < ActiveRecord::Base
class CreateUsers < ActiveRecord::Migration
                                               acts_as_nested_set
 def self.up
                                               acts_as_section_map
   create_table :users do ¦t¦
                                               has_many :users
    t.column :name, :string, :null=>false
                                              end
    t.column :section_id, :integer
   end
 end
 def self.down
   drop_table :users
 end
end


class User < ActiveRecord::Base
 belongs_to :section
end
データ作成

        userを作成し、sectionにぶら下げる
%   ./script/runner   'Section.find_by_name("Akasaka.rb").users   <<   User.create(:name=>"takai")'
%   ./script/runner   'Section.find_by_name("Akasaka.rb").users   <<   User.create(:name=>"koichiroo")'
%   ./script/runner   'Section.find_by_name("Akasaka.rb").users   <<   User.create(:name=>"takedasoft")'
%   ./script/runner   'Section.find_by_name("Asakusa.rb").users   <<   User.create(:name=>"a_matsuda")'
%   ./script/runner   'Section.find_by_name("Asakusa.rb").users   <<   User.create(:name=>"kakutani")'
%   ./script/runner   'Section.find_by_name("Asakusa.rb").users   <<   User.create(:name=>"maiha")'
ビューも直す
index.rhtml
<% section_map(@table2) do ¦table¦ %>
 <%=table.name%>
 <ul>
 <% table.users.each do ¦user¦%>
  <li><%=user.name%></li>
 <%end%>
 </ul>
<% end %>
見た目を直そう
index.rhtml
<% section_map(@table2,:table=>{:cellspacing=>"0",:style=>"border-collapse:collapse;"},
           :td=>{:valign=>"top",:style=>"border:1px solid #666666;color:navy;"}) do ¦table¦ %>
 <%=table.name%>
 <ul>
 <% table.users.each do ¦user¦%>
  <li style="font-size:12px;color:green"><%=user.name%></li>
 <%end%>
 </ul>
<% end %>
のろくない?



数が多いとのろいぞ
でも、なんとかしちゃる
でも今日はおしまい
続きは次回以降
イケテルDB
  チューニング

xibbarこと藤岡岳之
ブログのぶくま
これでぎりぎり卒論になるんじゃなかろうか。
長谷川がこけたら、これにしようかな。。。



     なんだこれ!!
巨大な組織

(1..4).each{¦n¦Section.create(:name=>"Section:#{n}")}
(5..60).each{¦n¦2.times{¦m¦
Section.find_or_create_by_name("Section:#{n*2+m
+3}").move_to_child_of
Section.find_by_name("Section:#{n}")}}




  120組織のツリーを作るスクリプト
遅すぎる

 User Load (0.000204) SELECT * FROM users
WHERE (users.section_id = 124)
Completed in 18.13171 (0 reqs/sec) ¦ Rendering:
7.49291 (41%) ¦ DB: 10.46457 (57%) ¦ 200 OK
[http://localhost/welcome]


            表示に18秒っておい!
インデックスを張ってみる

 User Load (0.000182) SELECT * FROM users
WHERE (users.section_id = 124)
Completed in 10.01978 (0 reqs/sec) ¦ Rendering:
6.97071 (69%) ¦ DB: 2.87357 (28%) ¦ 200 OK
[http://localhost/welcome]

             10秒に短縮!
          まだ使い物にならないけど
すばやさの種を投入
class AddDepthToSections < ActiveRecord::Migration
 def self.up
   add_column :sections,:depth,:integer
   Section.set_depth
 end


 def self.down
  remove_column :sections,:depth
 end
end


  depthという項目を追加し、
  値をセットする。depthというのは
  文字通り深さの値(levelの結果)
すばやさの種の結果

 User Load (0.000180) SELECT * FROM users WHERE
(users.section_id = 124)
Completed in 0.84391 (1 reqs/sec) ¦ Rendering: 0.40329 (47%) ¦
DB: 0.27316 (32%) ¦ 200 OK [http://localhost/welcome]




         1秒切ってメデタシメデタシ
ちょっとだけ解説



のろさの原因はsectionが自分自身の深さを
知るためにselect count(*)していることに
ある。(levelメソッド)
これをカラムとして持つとツリーの構築の早
さが圧倒的に違う(つまりdepthカラム)
benchmark
% ./script/performance/benchmarker 100 'Section.find(:all).map(&:level)'
        user   system   total   real
#1    5.790000 0.470000 6.260000 ( 10.331682)

% ./script/performance/benchmarker 100 'Section.find(:all).map(&:depth)'
        user   system   total   real
#1    0.610000 0.010000 0.620000 ( 0.784886)


                ちなみにindex張る前は
% ./script/performance/benchmarker 100 'Section.find(:all).map(&:level)'
        user   system   total   real
#1    6.180000 0.530000 6.710000 ( 20.693455)


            20.693 0.784=26.394
                  26倍早くなった!!
グー

おしまい


       http://www001.upp.so-net.ne.jp/masa_gallery/edo.html

More Better Nested Set