问候,全部,
我正在使用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
类型使用单表继承(例如,WordpressService
,FacebookService
,TwitterService
,并简单地序列化一个简单的哈希来保存身份验证数据)并使用传统的规范化方案,其中每种类型的服务都是自己的模型和表。我希望能够轻松地遍历与用户关联的所有服务,并且发布需要能够与任何类型的服务相关联(例如,发布可能会发送到WordPress,Facebook或Twitter)
我可以使用传统的规范化方法实现这种模型关系吗?或者这正是STI要解决的问题?
感谢。
答案 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
答案 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