将旧有的Acts_As_Tree转成Acts_As_Threaded

本文介绍了一种树状结构数据模型的迁移方法,通过增加root_id、lft、rgt及depth字段,实现了对子代数据的高效查询。文章提供了具体的迁移脚本和模型更新示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转换的重点其实只有一个,重点在于lft和rgt两个字段的初始化,否则其他字段的初始
化对会写程序的人应该难不倒才是,转换的相异点来自于新增四个字段:root_id(根ID)
、lft(左值)、rgt(右值)、depth(深)

改成这样好处多多,可以使用单一query取得"所有"子代(不限阶层),且所有子代count
详情请参阅Acts_As_Threaded

以下是转换实做的部份,用于"Cate"这个model
[b][[Migrate]][/b]

class FixCate < ActiveRecord::Migration 
def self.up
puts "fixing Cate"
Cate.reset_column_information
Cate.find(:all).each do |c|
if c.parent_id == nil
c.parent_id = 0
c.update
end
end
puts "fixed Cate"
change_column "cates" , "parent_id", :integer, :default => 0, :null => false
add_column "cates" , "root_id", :integer, :default => 0, :null => false
add_column "cates" , "lft", :integer
add_column "cates" , "rgt", :integer
add_column "cates" , "depth", :integer, :default => 0, :null => false
puts "fixing Cate"
Cate.reset_column_information
Cate.find(:all).each do |c|
if c.parent_id == 0
c.root_id = c.id
c.update
end
end
puts "fixed Cate"
end

def self.down
change_column "cates" , "parent_id", :integer
remove_column "cates" , "root_id"
remove_column "cates" , "lft"
remove_column "cates" , "rgt"
remove_column "cates" , "depth"
puts "fixing Cate"
Cate.reset_column_information
Cate.find(:all).each do |c|
if c.parent_id == 0
c.parent_id = nil
c.update
end
end
puts "fixed Cate"
end
end


[b][[cate.rb (Model)]] [/b]
class Cate < ActiveRecord::Base 
acts_as_threaded
def parent
if self.parent_id == 0
return nil
else
return Cate.find(self.parent_id)
end
end
def children
#direct_children与all_children选一个使用
return self.direct_children
end
end

[[cates_controller.rb (Controller)]]
class CatesController < ApplicationController
def init
Cate.find(:all).each do |c|
c.before_create
c.after_create
end
end
end


简单的来说,就是在migrate时做基本的转换与初始化,将parent_id = null转为parent_id = 0,然后将parent_id = 0的实体(root)的root_id改为自己(self.id),这样就完成基本的两个字段的初始化。

Model内新增两个method来复写掉继承的mothod,Acts_As_Threaded预设没有parent与children这两个method,且如果之前用Acts_As_Tree实做的话,通常root实体的parent的值通常为null,而修正后会变为0,所以需要另外复写。

因为migrate没有支持完整的Rails与AR与plugin,所以最后一步的初始化要留到全部建立好后,在Controller内执行才行,上面的Controller内写的init就是初始化的方式,执行一次即可。

如果详细看Acts_As_Threaded内的语法就会得知lft与rgt的migeate为何没加入":default => 0, :null => false"这段语法与为何要那样的初始化,不过还是希望有神人可以想出在migrate内一次做完全部的方法 :)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值