【问题标题】:What's the best way to share user accounts between the application and an engine?在应用程序和引擎之间共享用户帐户的最佳方式是什么?
【发布时间】:2015-07-16 19:30:28
【问题描述】:

我有一个包含UserGroup 模型的网站,一切都很好。 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::UserBilling::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 =&gt; "::#{base}"
  • 这似乎没有帮助......该模块中的代码在 UserGroup 被加载之前不会被执行。

标签: ruby-on-rails ruby activerecord rails-engines


【解决方案1】:

一种方法是在引擎中添加一个模块,将类宏添加到UserGroup

class User < ActiveRecord::Base
  include Billing::ModelHelper
  has_subscription # new macro
end

has_subscription 可以:

  • 查找类名 (User)
  • has_many/has_one/belongs_to 关联添加到User
  • 将特殊关联添加到Billing::Subscription (belongs_to :user, ...)

【讨论】:

  • 您能否提供一个示例,说明如何从该模块中向另一个类添加关系?我已经完成了添加has_one :subscription 的部分,但我不知道如何打开Billing::Subscription 以添加我的belongs_to :usersbelongs_to :groups。我尝试了谷歌搜索,但还是找不到任何相关的内容。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-05
  • 2019-01-31
  • 2011-11-06
  • 1970-01-01
相关资源
最近更新 更多