STI和扩展子类以在数据库中包含“额外”列?

时间:2011-02-08 20:15:34

标签: ruby-on-rails models sti

也许STI不是我想要的,我对所有建议持开放态度,但为了这个问题,让我们假设以下现实情况:

您希望自己的应用为不同的邮件供应商提供API数据。使用STI,您有以下模型

class MailSetting < ActiveRecord::Base
belongs_to :user

end


class MailChimp < MailSetting

end

class AWeber < MailSetting

end

class PostageApp < MailSetting

end

现在让我们做一些控制台动作:


user = User.first
setting = user.create_mail_setting(:type => "MailChimp")

好的,现在您要添加API密钥设置。 MailChimp只使用api_key。 Aweber可以使用api_key和签名,而Postageapp则使用api_key和令牌系统。

您是否会扩展每个子类以包含数据库中所需的任何列? 你是否会一起废弃STI,只是定期上课,MailChimp,继承自AR?

我对STI的理由是,我知道我的所有用户都会有一个MailSetting,这种类型可能会随着时间的推移而扩展。但是,我发现以这种方式扩展这些子类是一件很痛苦的事情,导致你不能在不知道它们是什么子类的情况下做user.mail_setting.connect这样的事情,然后,我需要连接这些人吗?

思想?

3 个答案:

答案 0 :(得分:3)

您应该使用Polymorphic类而不是STI

<强> UPD

一些链接:

UPD 2

想象一下,我们需要Post模型。我们有继承Post的文章和主题。

rails g model Post title:string body:text content_type:string content_id:integer

因此titlebody是主题和文章的常见字段。现在让我们在主题中创建user_id字段并在文章

中创建link的其他模型
rails g model Topic user_id:integer
rails g model Article link:string

现在我们将编辑模型:

class Post < ActiveRecord::Base
  belongs_to :content, :polymorphic => true, :dependent => :destroy
end

class Topic < ActiveRecord::Base
  has_one :post, :as => :content, :dependent => :destroy
end

class Article < ActiveRecord::Base
  has_one :post, :as => :content, :dependent => :destroy
end

它可能非常复杂,但是这样挖掘:)

答案 1 :(得分:2)

您可以考虑使用ActiveRecord::Store中的store_accessor方法。

STI商店方法given here演示了如何为各个子类提供不同的访问者,这些访问器被序列化到超类的单个列中。

如果您正在使用PostgreSQL&gt; = 9.2,那么这与其JSON类型完美配合,如果没有,那么您可以让Rails进行序列化(使用store代替store_accessor

TLDR(假设PostgreSQL&gt; = 9.2):

添加迁移:

add_column :mail_settings, :vendor_settings, :json

在子类中定义相关属性:

class MailChimp < MailSetting
    store_accessor :vendor_settings, :api_key
    validates :api_key, presence: true
end 

答案 2 :(得分:0)

在我看来,您的架构已经足够无形,以至于您最好使用无架构数据库。也许是基于“NoSQL”文档的解决方案之一?这样,您可以随意添加和删除记录中的字段。