在应用程序和引擎之间共享用户帐户的最佳方式是什么?
What's the best way to share user accounts between the application and an engine?
我的网站有 User
和 Group
模型,一切正常。用户和组模型是我们拥有的两种类型的帐户,它们目前用于联系信息、身份验证和授权。
现在我正在构建网站的订阅部分,这样我们就可以开始向订阅我们高级服务的用户(和 groups/organizations)收费。我选择将此新代码放入 Rails 引擎中,因为我希望仅将引擎部署到可通过我们的 VPN 访问的主机上的环境中,如下所示:
mount Billing::Engine, :at => '/billing' if Rails.env.admin?
我正在使用三个模型来管理订阅:
module Billing
class PricingPlan < ActiveRecord::Base
has_many :subscriptions
end
end
module Billing
class Subscription < ActiveRecord::Base
belongs_to :pricing_plan
belongs_to :subscriber, :polymorphic => true
# Used for eager loading
belongs_to :users, :foreign_key => 'subscriber_id', :class_name => '::User'
belongs_to :groups, :foreign_key => 'subscriber_id', :class_name => '::Group'
has_many :payments
end
end
module Billing
class Payments < ActiveRecord::Base
belongs_to :subscription
end
end
Billing::Subscription.subscriber
部分是目前让我烦恼的部分。如您所见,我目前正在跨越引擎边界获取应用程序中存在的 ::User
和 ::Group
模型,但这感觉很糟糕。
我考虑过创建 Billing::User
和 Billing::Group
AR 模型,以便引擎和应用程序可以完全相互隔离,但是在两个模型之间复制信息似乎有点奇怪,现在,在同一个数据库中(例如 first_name、last_name、电子邮件等)...而且我必须在它们之间复制信息,这是灾难的根源,我'我确定。
我还考虑过使用某种包装模型来抽象出实际的实现,像这样:
module Billing
class User < ::User
end
end
但是如果我没记错的话,我 运行 遇到了多态行为的问题 我在 and/or 问题之后 rspec 模拟和存根,所以我放弃了这种方法。
如有任何指导,我将不胜感激。我曾多次前往 Google 寻找答案,但到目前为止我所看到的似乎都没有直接适用。
更新
根据 Carl Zulauf 的建议,我得出以下结论:
# File: app/models/concerns/billing/subscribable.rb
require 'active_support/concern'
module Billing
module Subscribable
extend ActiveSupport::Concern
included do
has_one :subscription, {
:class_name => '::Billing::Subscription',
:foreign_key => 'subscriber_id',
:as => :subscriber
}
base = self
Billing::Subscription.class_eval do
belongs_to base.name.tableize.to_sym, {
:foreign_key => 'subscriber_id',
:class_name => base.to_s
}
end
end
end
end
然后我这样调用:
class User < ActiveRecord::Base
include Billing::Subscribable
can_subscribe
end
这行得通...只要我在 之前加载 User
我调用 Billing::Subscription.eager_load :users
...这看起来真的很冒险。对我有什么建议吗?
更新 #2
我最终创建了一个初始化程序来处理这个问题。这行得通,但如果有更好的选择,我会洗耳恭听。
# File: config/initializers/setup_billing.rb
User.class_eval do
include Billing::Subscribable
end
Group.class_eval do
include Billing::Subscribable
end
一种方法是在您的引擎中添加一个模块,将 class 宏添加到 User
和 Group
.
class User < ActiveRecord::Base
include Billing::ModelHelper
has_subscription # new macro
end
has_subscription
然后可以:
- 查找 class 名称 (
User
)
- 将
has_many
/has_one
/belongs_to
关联添加到 User
- 将特殊关联添加到
Billing::Subscription
(belongs_to :user, ...
)
我的网站有 User
和 Group
模型,一切正常。用户和组模型是我们拥有的两种类型的帐户,它们目前用于联系信息、身份验证和授权。
现在我正在构建网站的订阅部分,这样我们就可以开始向订阅我们高级服务的用户(和 groups/organizations)收费。我选择将此新代码放入 Rails 引擎中,因为我希望仅将引擎部署到可通过我们的 VPN 访问的主机上的环境中,如下所示:
mount Billing::Engine, :at => '/billing' if Rails.env.admin?
我正在使用三个模型来管理订阅:
module Billing
class PricingPlan < ActiveRecord::Base
has_many :subscriptions
end
end
module Billing
class Subscription < ActiveRecord::Base
belongs_to :pricing_plan
belongs_to :subscriber, :polymorphic => true
# Used for eager loading
belongs_to :users, :foreign_key => 'subscriber_id', :class_name => '::User'
belongs_to :groups, :foreign_key => 'subscriber_id', :class_name => '::Group'
has_many :payments
end
end
module Billing
class Payments < ActiveRecord::Base
belongs_to :subscription
end
end
Billing::Subscription.subscriber
部分是目前让我烦恼的部分。如您所见,我目前正在跨越引擎边界获取应用程序中存在的 ::User
和 ::Group
模型,但这感觉很糟糕。
我考虑过创建 Billing::User
和 Billing::Group
AR 模型,以便引擎和应用程序可以完全相互隔离,但是在两个模型之间复制信息似乎有点奇怪,现在,在同一个数据库中(例如 first_name、last_name、电子邮件等)...而且我必须在它们之间复制信息,这是灾难的根源,我'我确定。
我还考虑过使用某种包装模型来抽象出实际的实现,像这样:
module Billing
class User < ::User
end
end
但是如果我没记错的话,我 运行 遇到了多态行为的问题 我在 and/or 问题之后 rspec 模拟和存根,所以我放弃了这种方法。
如有任何指导,我将不胜感激。我曾多次前往 Google 寻找答案,但到目前为止我所看到的似乎都没有直接适用。
更新
根据 Carl Zulauf 的建议,我得出以下结论:
# File: app/models/concerns/billing/subscribable.rb
require 'active_support/concern'
module Billing
module Subscribable
extend ActiveSupport::Concern
included do
has_one :subscription, {
:class_name => '::Billing::Subscription',
:foreign_key => 'subscriber_id',
:as => :subscriber
}
base = self
Billing::Subscription.class_eval do
belongs_to base.name.tableize.to_sym, {
:foreign_key => 'subscriber_id',
:class_name => base.to_s
}
end
end
end
end
然后我这样调用:
class User < ActiveRecord::Base
include Billing::Subscribable
can_subscribe
end
这行得通...只要我在 之前加载 User
我调用 Billing::Subscription.eager_load :users
...这看起来真的很冒险。对我有什么建议吗?
更新 #2
我最终创建了一个初始化程序来处理这个问题。这行得通,但如果有更好的选择,我会洗耳恭听。
# File: config/initializers/setup_billing.rb
User.class_eval do
include Billing::Subscribable
end
Group.class_eval do
include Billing::Subscribable
end
一种方法是在您的引擎中添加一个模块,将 class 宏添加到 User
和 Group
.
class User < ActiveRecord::Base
include Billing::ModelHelper
has_subscription # new macro
end
has_subscription
然后可以:
- 查找 class 名称 (
User
) - 将
has_many
/has_one
/belongs_to
关联添加到User
- 将特殊关联添加到
Billing::Subscription
(belongs_to :user, ...
)