Rails之单表继承(Single Table Inheritance)

Rails之单表继承

什么时候使用:
    假设我们的应用中有三个模型相似的东西,我们假设现在有汽车,卡车,摩托车这三种模型,
在rails中我们建模有三种选择
 Polymorphic Associations (separate classes, multiple tables)多态关联,单独的类,多个表
 Single Table Inheritance (separate classes, one table)  单表继承, 单独的类,多个表
 Single Class with conditionals (one class, one table)   一个类, 一个表

在多态关联中,使用module来共享各个类之间代码,而Single Class也不能称为是一种设计模式,
当各个模型之间只有细微的差别时,就可以考虑使用单表继承(STI)

当我们决定如何设计数据模型的时候,我们首先要问自己几个问题

1.是所有的对象都继承自一个类吗?
    比如,汽车,卡车,摩托车都可以认为是机动车的子类, 但是如果现在加入了自行车,手推车呢,
似乎就不合理了,也就是说不要为了共享属性,比如轮子的个数,颜色等属性而使用单表继承,
而且要揣摩父类的命名如何能更合理

2.是否需要对数据库中的所有对象进行查询操作?
    如果你像查询出所有对象或者做一些聚合查询的时候,你可能希望所有的数据都在一张表中。
即使rails中的joins或者ActiveRecord对sql做了优化,数据分离给数据库操作带来复杂性的增加是不值得的,
总的来说,完全的数据归一化往往并不是最好的设计

3.是所有对象都有相同的属性,但是不同的行为吗?
    数据库中有多少列是各个类所共享的,如果每个类有过多的特殊属性,那么就不建议使用单表继承,
而使用多态关联,因为使用单表继承会导致数据库中冗余的信息过多

在rails中如果使用单表继承:(这里使用的是rails4)

这里为了举例方便,使用Boy, Girl, User三个类,也就是说boy和girl都继承自User类

使用rails脚手架生成模型User,注意这里会为User创建一个字符串类型的type字段,用与标示子类
 rails g scaffold user name:string age:integer type:string
 rake db:migrate

 在user.rb文件中,常见Girl和Boy类,分别继承自User类
class User < ActiveRecord::Base
end

然后分别创建 app/models/girl.rb,  app/models/boy.rb, Boy和Girl分别继承自User类
class Boy<User; end
class Girl<User; end

最关键一步在这里,需要在user类中重写inherited方法,当有任意一个类继承User的时候,触发该函数
然后重写莫model_name方法,返回User.model_name,因为此时Boy和Girl都会存在Users表里,以及对Girl和Boy
的操作实际上也都是在user上,在Rails中通过model_name 来控制, 此时User Girl 和Boy的model_name都是相同
的 实际上就是一个ActiveModel::Name对象,因此对Girl和Boy的操作会转到User上

2.1.1 :001 > User.model_name

 => #<ActiveModel::Name:0x007fe1d1b5e8b0 @name="User", @klass=User (call 'User.connection' to establish a connection), @singular="user", @plural="users", @element="user", @human="User", @collection="users", @param_key="user", @i18n_key=:user, @route_key="users", @singular_route_key="user”>

class User < ActiveRecord::Base
def self.inherited(child)
     child.instance_eval do
       def model_name
          User.model_name
       end
     end
     super
end
end

你可能感兴趣的:(sti,单表继承)