act_as_list : one-to-many对象关系是通过list(默认是set)来完成, 既然有list, 就有了排序,首先对应表中必须有position(自动默认)字段,用来标示排序,如果不默认就得显示通过:order指定
class Parent < ActiveRecord::Base
has_many :children, :order => :position
end
class Child < ActiveRecord::Base
belongs_to :parent
acts_as_list :scope => :parent_id
end
这里的:scope=> :parent_id 说明了list是相对于单个parent_id的, 否则就是所有的product共用一个排序
对应关系建立以后, child对象会增加如下move_lower,move_higher, move_to_top,move_to_bottom,还会有first?和last?方法
注意 对对象作了排序操作以后, 只是修改数据库中的记录, parent对象还不会在list中调整, 必须调用parent.reload
和act_as_list类似,例子如下
class Category < ActiveRecord::Base
acts_as_tree :order=> "name"
end
实际上这个代码等同于===>
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
通过children操作, 如有必要,可以通过:counter_cache=> true 并添加children_count来优化子对象数量获取
简单的说就是把几个字段映射为一个字段,方法为新建立一个对象 class Name attr_reader :first,:last end 然后在主对象中使用composed_of
class XX < ActiveRecord::Base
composed_of :name, :class_name=>Name,:mapping=>
[
[:first_name,:first]
[:last_name,:last]
]
end
其中:class_name和mapping可省略 ???
aggregation还可以用来聚合单一字段,下面的类就聚合了一个字段(以,号分隔)
class XxYy
attr_reader :list
def initialize(db_str)
@list=db.str.split(/,/)
end
def xx_yy
@list.join(',')
end
end
然后主类需要用composed_of 标明映射的字段xx_yy
class Main
composed_of :xx_yy
end
注意 aggregation对象都是value object, 你不能修改他里面的值,即使修改了,rails也不会回写它们到数据库中,唯一修改的办法是新建另外一个component然后赋给主对象
只适用于大部分值都在父类的对象结构, 对于abstact方法的对象结构(子类直接差别非常大),可能不适合
实现这三个方法就可以自动使用validate, 手动调用的方法是valid?()
validate就是简单的判断, 然后再errors.add(:xxxx,"readon")就可以,例子如下
class User < ActiveRecord::Base
def validate
unless name && name =~ /^\w+$/
errors.add(:name, "is missing or invalid")
end
end
def validate_on_create
if self.find_by_name(name)
errors.add(:name, "is already being used")
end
end
end
提示 rails增加了一个blank?方法 可以判断string为nil或""
大部分指令都支持:on和:message参数,
失败以后,controller会自动重新显示form,然后page可以通过调用error_messages_for()来显示错误消息
指令列表如下
一共16个callback, 其中14个如下图调用 (可以看出没有严格嵌套)
另外两个特殊的callback是after_find after_initialize
callback的注册可以通过
要统一注册callback ,可以修改ActiveRecord::Base根类
注意 字段created_at created_on updated_at updated_on会自动被rails更新
默认在app/model下一个典型的例子, 如果不使用observe类指令, 默认是根据类名推导出来为Audit类
class AuditObserver < ActiveRecord::Observer observe Order, Payment, Refund def after_save(model) model.logger.info("#{model.class.name} #{model.id} created") end end
最后要调用一下 XXXObserver.instance方法才能生效, 在rails中可以在controller中使用observe方法,不用单独instance了
model.attributes可以取得属性hash,可以访问特殊名的字段
特殊的组合sql可能无法得到字段类型(mysql5.0好像没有这个问题了),导致rails以文本方式保存数据,这时我们可以通过调用read_attribute("xxx")和write_attribute("xxx")可以直接在底层操作数据,作一些转换来构造一个facade column来满足需求,例子如下
class ProductData < ActiveRecord::Base
CUBITS_TO_INCHES = 18
def length
read_attribute("length") * CUBITS_TO_INCHES
end
def length=(inches)
write_attribute("length", Float(inches) / CUBITS_TO_INCHES)
end
end