Ох уж эти деревья ... В Spree .9.2 изменили дерево таксонов (иерархию групп продуктов) по сравнению с .9.0 со своей модификации atcs_as_tree на acts_as_nested_sets, и моя выгрузка данных из 1С на этом переходе обломилась. Естественно пошел в интернет искать информацию о том как сделать из списка смежности (дерево: объект, родитель, ...) вложенные множества (объект, родитель, левое, правое, ...). В русском сегменте встретил только теоретическую информацию об устройстве nested sets, выгодах получаемых при выборке и тормозах при обновлении (при переносе вершины нужно пересчитать все дерево).
SQL ответ нашелся в древней статье 97 года самого автора такой модели вложенных множеств - Деревья в SQL, ... а Ruby ответ нашелся в папке с миграциями и был быстро преобразован в Rake Task. И если первый сможете прочесть у автора - второй опубликую (кстати он гораздо короче SQL-варианта)
desc "update taxons to nestedset"
task :upd_taxons => :environment do
Taxon.class_eval do
# adapted from awesome nested set to use "position" information
indices = {}
left_column_name = "lft"
right_column_name = "rgt"
quoted_parent_column_name = "parent_id"
scope = lambda{|node|}
set_left_and_rights = lambda do |node|
# set left
node[left_column_name] = indices[scope.call(node)] += 1
# find
find(:all, :conditions => ["#{quoted_parent_column_name} = ?", node], :order => "position ASC").each{|n| set_left_and_rights.call(n) }
# set right
node[right_column_name] = indices[scope.call(node)] += 1
node.save!
end
# Find root node(s)
find(:all, :conditions => "#{quoted_parent_column_name} IS NULL", :order => "position ASC").each do |root_node|
# setup index for this scope
indices[scope.call(root_node)] ||= 0
set_left_and_rights.call(root_node)
end
end
end
ЗЫ
Design Patterns исполнилось 15 лет - читайте посвященное этому событию
интервью с авторами книги