代码之家  ›  专栏  ›  技术社区  ›  Michelle Tilley

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

  •  2
  • Michelle Tilley  · 技术社区  · 14 年前

    大家好,

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

    每个用户都可以在应用程序中创建日志,我们将接收这些日志并将它们发送到外部服务,以便为用户发布。然后我们跟踪对已发布帖子的回复(Twitter上的转发、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 类型(例如, WordpressService , FacebookService , TwitterService ,然后简单地序列化一个简单的哈希以保存身份验证数据),并使用传统的规范化方案,其中每种类型的服务都是它自己的模型和表。我希望能够轻松地迭代与用户关联的所有服务,并且发布需要能够与任何类型的服务关联(例如,发布可能发送到WordPress、Facebook或Twitter)。

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

    谢谢。

    4 回复  |  直到 13 年前
        1
  •  2
  •   Abe    14 年前

    您可能想查看 omniauth plugin 这是非常容易设置和处理存储一些现成服务的身份验证凭证。有几个铁路公司演示如何设置它。如果没有别的,你可以看到他们建议如何存储东西。

        2
  •  2
  •   Pedro Rolo    13 年前

    作为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
    

    This this 可能对你有帮助。

        3
  •  0
  •   Stephanie Page    14 年前

    您将存储多少用户,每秒查询多少次表?一般来说,您的物理设计会受到这种类型的存储的影响,但硬件将克服设计中对大量应用程序的缺陷。如果你不进行大规模的日期交易或大额交易,你会很好地处理任何你提出的问题。

        4
  •  0
  •   Michelle Tilley    14 年前

    虽然我仍然不确定它是否是解决这个问题的“正确”方法,但是我已经决定使用单表继承,这样我可以很容易地得到 全部的 另一种模式的服务 has_many 的(因为 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
    

    服务 还知道它的子类,以便可以轻松创建菜单等:

    class Service < ActiveRecord::Base
    
      @child_classes = []
    
      ...
    
      protected
    
        def self.inherited(child)
          @child_classes << child
          super
        end
    
        def self.child_classes
          @child_classes
        end
    end