acts as list/acts as tree

[color=red]Acts As List[/color]

在子表中使用acts_as_list,便能从父表的“视图”中得到像子表的行为。父表将能够
遍历子表,在列表内移动子表,或从列表内移除子表。
通过给每个子表一个位置数来实现列表。这意味着子表必须有个列来记录此位置。如果
我们称它为列position,Rails 会自动使用它。如果不这么称呼它,我们需要告诉Rails 它
的名字。对于我们的例子,跟随父表之后我们将创建一个新的子表(叫children)。
create table parents (
id int not null auto_increment,
primary key (id)
);
create table children (
id int not null auto_increment,
parent_id int not null,
name varchar(20),
position int,
constraint fk_parent foreign key (parent_id) references parents(id),
primary key (id)
);
接着,我们将创建“模型”类。注意在Parent 类中,我们基于当前的position 列的值
来确定我们children 的位置。这确保从数据库内获得的数组在正确的定单清单内。
class Parent < ActiveRecord::Base
has_many :children, :order => :position
end
class Child < ActiveRecord::Base
belongs_to :parent
acts_as_list :scope => :parent_id
end
在Child 类中,我们用传统的belongs_to 声明来建立与父表的连接。我们也有个
acts_as_list 声明。我们用一个:scope 选项来限制它,指定列表的每个父表。没有这范围操
作符,则对于children 表内的所有条目则只有一个全局的列表。
现在我们设一些测试用数据:我们为一个特定的父项创建四个子项,称为One,Two,Three
和Four。
parent = Parent.new
%w{ One Two Three Four}.each do |name|
parent.children.create(:name => name)
end
parent.save
我们要写个简单的方法来检查列表的内容。
def display_children(parent)
puts parent.children.map {|child| child.name }.join(", ")
end
在完成我们列表的测试后。注释显示了由display_children()产生的输出。
display_children(parent) #=> One, Two, Three, Four
puts parent.children[0].first? #=> true
two = parent.children[1]
puts two.lower_item.name #=> Three
puts two.higher_item.name #=> One
parent.children[0].move_lower
parent.reload
display_children(parent) #=> Two, One, Three, Four
parent.children[2].move_to_top
parent.reload
display_children(parent) #=> Three, Two, One, Four
parent.children[2].destroy
parent.reload
display_children(parent) #=> Three, Two, Four
注意我们是如何在父项中调用reload()的。各种move_method 更新数据库内子项,但因
为它们直接操作子项,父项将不会立即知道这一更改。
list 库使用术语lower 和higher 来引用元素的相对位置。Higher 意味着离列表前部近,
lower 离尾部近。顶部也与前部是一个意思,底部与尾部是一个意思。方法move_higher( ),
move_lower( ), move_to_bottom( ), 和move_to_top( ) 在list 内循环移动一个特定项
目,并自动调整与其它元素的位置。
higher_item( ) 和lower_item( ) 返回相对于当前元素的下一个和前一个元素的位
置, first?( ) 和last?( ) 在list 内的当前元素位于前部或尾部时返回true 。
新近创建的子项被自动地添加到列表的尾部。当一个子行被删除时,list 内的子项会被
移除并用gap 填充。


[color=red]Acts As Tree[/color]

“活动记录”提供对组织一个表内的行到一个层次,或树,结构中的支持。这对创建具
有子项的项目很有用处,并且这些子项还可以有它自己的子项。分类目录列表通常有这种结
构,如对许可证,目录清单等等的描述。
这种类似树的结构可通过向表中添加一个单独的列(缺省称为parent_id)来做到。这个
列是个引用自身表的外键,链接子行到它们的父行。图15.1 演示了它。
要显示出树是如何工作的,让我们创建个简单的分类表,每个顶层分类有子分类,每个
子分类可以添加子分类层。注意外键指回到自身表中。
create table categories (
id int not null auto_increment,
name varchar(100) not null,
parent_id int,
constraint fk_category foreign key (parent_id) references
categories(id),
primary key (id)
);
相应的“模型”使用带有种类名字acts_as_tree 的方法来指出这种关系。:order 参数
意味着当我们查找特定节点的子项时,我们会看到它们按它们名字列被重新排列。
class Category < ActiveRecord::Base
acts_as_tree :order => "name"
end
通常你得有一些最终用户功能来创建和管理分类层次。这儿,我们只使用创建它的代码。
注意我们如何使用子项属性来管理任何节点的子项。
root = Category.create(:name => "Books")
fiction = root.children.create(:name => "Fiction")
non_fiction = root.children.create(:name => "Non Fiction")
non_fiction.children.create(:name => "Computers")
non_fiction.children.create(:name => "Science")
non_fiction.children.create(:name => "Art History")
fiction.children.create(:name => "Mystery")
fiction.children.create(:name => "Romance")
fiction.children.create(:name => "Science Fiction")
现在我们做好了所准备工作,我们可以试用树结构了。我们使用我们用于list 代码的
display_children()方法。
display_children(root) # Fiction, Non Fiction
sub_category = root.children.first
puts sub_category.children.size #=> 3
display_children(sub_category) #=> Mystery, Romance, Science Fiction
non_fiction = root.children.find(:first, :conditions => "name = 'Non
Fiction'")
display_children(non_fiction) #=> Art History, Computers, Science
puts non_fiction.parent.name #=> Books
我们用于操纵子项的各种方法看起来很熟悉:它们与提供给has_many 的是一样的。事实
上,如果我们看看acts_as_tree 的实现,我们将看到这做的所有事情都是构建在belongs_to
和has_many 属性上,每个都指回自身表。就像我们写的一样。
class Category < ActiveRecord::Base
belongs_to :parent,
:class_name => "Category"
has_many :children,
:class_name => "Category",
:foreign_key => "parent_id",
:order => "name",
:dependent => true
end
如果你需要优化子项大小的性能,你可以构建一个counter 缓存(就好像你在用
has_many)。添加选项:counter_cache => true 给acts_as_tree 声明,添加列
children_count 给你的表。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值