单表继承是我的Rails问题的正确解决方案吗?

时间:2010-09-22 04:33:37

标签: database-design activerecord ruby-on-rails-3 single-table-inheritance

问候,全部,

我正在使用Ruby on Rails中的应用程序,我们需要跟踪应用程序的每个用户(例如,Facebook,MySpace,Google,SalesForce,Twitter,WordPress等)的一堆外部服务将代表用户访问。对于某些服务,我们需要存储(加密的)用户名和密码,对于某些服务,我们需要保存OAuth数据,某些OAuth2数据,等等。随着应用程序的增长,我们需要支持更多类型的帐户,每个帐户都有自己的一组身份验证数据。

每个用户都可以在应用程序中创建帖子,我们将把这些帖子发送给外部服务,以便为用户发布。然后我们跟踪对已发布帖子的回复(推特上的推文,Facebook上的喜欢/分享等)。

所以:

class User < ActiveRecord::Base
  has_many :services
  has_many :posts
end

class Post < ActiveRecord::Base
  belongs_to :user
  has_many :publishes
end

class Publish < ActiveRecord::Base
  has_one :service
  belongs_to :post
end

class Service < ActiveRecord::Base
  belongs_to :user
  belongs_to :publish
end

我正在讨论对我的Service类型使用单表继承(例如,WordpressServiceFacebookServiceTwitterService,并简单地序列化一个简单的哈希来保存身份验证数据)并使用传统的规范化方案,其中每种类型的服务都是自己的模型和表。我希望能够轻松地遍历与用户关联的所有服务,并且发布需要能够与任何类型的服务相关联(例如,发布可能会发送到WordPress,Facebook或Twitter)

我可以使用传统的规范化方法实现这种模型关系吗?或者这正是STI要解决的问题?

感谢。

4 个答案:

答案 0 :(得分:2)

您可能需要查看omniauth plugin,它很容易设置并处理存储许多服务的身份验证凭据。有几个railscast显示如何设置它。如果没有别的,你可以看到他们建议如何存储东西。

答案 1 :(得分:2)

作为STI的替代方案,您可以使用多态关联:

class AccountAuth < AR::Base
  belongs_to :account
  belongs_to :authentication, :polymorphic => true
end
# account_id          :integer
# authentication_id   :integer
# authentication_type :string

module Auth
  #common logic
end

class FacebookAuth < AR::Base
  include Auth
  has_one :account_auth,:as=>:authentication
  has_one :account, :through => :account_auth
end

class Account < AR::Base
  has_many :account_auths
  has_many :authentications, :through => :account_auths
end

Thisthis可能会对您有所帮助。

答案 2 :(得分:0)

您将存储多少百万用户,您每秒会查询多少次?我一般会说你的物理设计会受到这种类型的存储的影响,但硬件将克服大量应用程序的设计缺陷。如果您没有在大规模日期或大批量交易中操作,那么您可以处理任何事情。

答案 3 :(得分:0)

虽然我仍然不确定这是解决此问题的“正确”方法,但我决定使用单表继承,以便我可以轻松获取 all 的列表另一个模型has_many的服务(因为Service的每个子类也是Service,我可以调用model_instance.services来获取它们。

为了解决代码重复的问题,我创建了一个模块,用于任何应该has_many :services的模型以及每种类型的服务:

module HasServices
  extend ActiveSupport::Concern
  included do
    has_many :services
    has_many :facebook_services
    has_many :twitter_services
    has_many :wordpress_services
  end
end

Service也知道它的子类,因此可以轻松创建菜单等:

class Service < ActiveRecord::Base

  @child_classes = []

  ...

  protected

    def self.inherited(child)
      @child_classes << child
      super
    end

    def self.child_classes
      @child_classes
    end
end