【发布时间】:2015-07-16 19:30:28
【问题描述】:
我有一个包含User 和Group 模型的网站,一切都很好。 User 和 Group 模型是我们拥有的两种类型的帐户,它们目前用于联系信息、身份验证和授权。
现在我正在构建网站的订阅部分,以便我们可以开始向订阅我们的高级服务的用户(和团体/组织)收费。我选择将此新代码放入 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 模型,以便引擎和应用程序可以完全相互隔离,但是在两个模型之间复制信息似乎有点奇怪,目前,在相同的数据库(例如名字、姓氏、电子邮件等)...另外,我必须在它们之间复制信息,我敢肯定,这会导致灾难。
我还考虑过使用某种包装模型来抽象出实际的实现,如下所示:
module Billing
class User < ::User
end
end
但如果我没记错的话,我遇到了我所追求的多态行为问题和/或 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
【问题讨论】:
-
要处理必须首先加载
User的问题,您可以尝试将一元 (::) 运算符放在类名之前。:class_name => "::#{base}" -
这似乎没有帮助......该模块中的代码在
User或Group被加载之前不会被执行。
标签: ruby-on-rails ruby activerecord rails-engines