单表继承用于引用具有自己字段的子类

时间:2011-05-04 12:05:04

标签: ruby-on-rails ruby ruby-on-rails-3 class single-table-inheritance

我正在使用Ruby on Rails 3,我实现了一个有效的单表继承,如下所示:

class User < ActiveRecord::Base

  # Schema Information
  #
  # Table name: User
  #
  # id              : integer
  # type            : string
  # children_user_id: integer

  ...
end

class UserAdmin < User

  # Schema Information
  #
  # Table name: UserAdmin
  #
  # id             : integer
  # special_field1 : string
  # special_field2 : string
  # ...

  ...
end

class UserCommon < User

  # Schema Information
  #
  # Table name: UserCommon
  #
  # id             : integer
  # another_field1 : string
  # another_field2 : string
  # ...

  ...
end

我想知道,在运行以下内容的UserAdmin表格中创建UserCommon记录(或User记录)

UserAdmin.create(:children_user_id => "1")
# or UserCommon.create(:children_user_id => "1")

可以在UserAdmin表(或UserCommon表中)以某种方式“自动”创建(可能是“ Rails Way ”!)新记录它有自己的字段(在数据库级别,这些字段是列)。 我想这样做是为了“更好地处理”UserAdmin,因为此类具有UserCommon类的不同和更多属性。

如果有可能,我该怎么做(可能使用关联模型语句,回调,多态,......) 你有吗?关于这个问题的建议?

1 个答案:

答案 0 :(得分:7)

具有单表继承的东西是基于单个表模型,这并不奇怪,因此您不能使用不同的表来使用不同的类。

通常,“Rails方式”是将所有可能的字段捆绑到一个表中,并使用STI为您处理数据映射和验证问题。但是,它可以从应用程序中隐藏的内容存在限制,因为通常定义的字段意味着它可以被绑定到该表的任何类使用。大多数人不认为这是一个问题。

您可能想要做的是根据用户类型创建一个加入的记录,例如:

class User < ActiveRecord::Base
end

class AdminUser < User
  belongs_to :admin_profile
end

class CommonUser < User
  belongs_to :common_profile
end

这需要users表格包含admin_profile_idcommon_profile_id列,其中admin_profilescommon_profiles表格包含所需的其他字段。

可以根据需要使用delegate方法将这些表中的属性映射回基类。

将额外字段移动到单独的表中可能有助于划分事物,但这也意味着由于所需的连接而导致读取速度变慢,并且由于一个部分缺失或过期而导致记录不一致的可能性增加。

通常,您可以将所有与用户相关的字段加载到单个表中,即使不经常使用其中许多字段也是如此。事物方案中NULL字段的存储成本通常很低,除非有数百个这样的字段,否则暴露给开发人员的额外复杂性是最小的,要付出的代价要小于必须不断创建和引用记录的成本。