Rails Rails 之单表继承 (Single Table Inheritance)

michael_roshen · 2014年09月24日 · 最后由 MrTentacle 回复于 2020年05月27日 · 6897 次阅读

前一段时间听朋友说到 rails 的单表集成 STI, 抽空查了一些资料,这里分享给大家,不足之处请多指教~ 原文地址:http://michael-roshen.iteye.com/blog/2119766/

也可以关注私人微信订阅号:ruby 程序员(注册的时候没想到好名字,现在改不了了,纯野性自然生长,目前已有 87 个关注者了,近期在弄一些 hadoop 的东西,有两个月没有维护了,不过关注人数还在增长,也欢迎时间充沛的朋友可以加入进来)

什么时候使用: 假设我们的应用中有三个模型相似的东西,我们假设现在有汽车,卡车,摩托车这三种模型, 在 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

=> #

class User < ActiveRecord::Base
  def self.inherited(child)
     child.instance_eval do
       def model_name
          User.model_name
       end
     end
     super
  end
end
chenyunli [该话题已被删除] 提及了此话题。 10月18日 16:36

错字连篇 阅读体验极差 要不是我小学语文是体育老师教的 恐怕我都看不明白...😆

需要 登录 后方可回复, 如果你还没有账号请 注册新账号