在应用程序和引擎之间共享用户帐户的最佳方式是什么?

时间:2015-07-16 19:30:29

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

我的网站有UserGroup个模型,一切都很好。用户和组模型是我们拥有的两种类型的帐户,它们目前用于联系信息,身份验证和授权。

现在,我正在构建网站的订阅部分,以便我们开始为订阅我们的高级服务的用户(和团体/组织)收费。我选择将这个新代码放在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模型,以便引擎和应用程序可以完全隔离,但是在两个模型之间复制信息似乎有点奇怪现在,在同一个数据库中(例如first_name,last_name,email等)......加上我必须在它们之间复制信息,这是一个灾难的秘诀,我确定。

我还想过使用某种包装模型来抽象出实际的实现,如下所示:

module Billing
  class User < ::User
  end
end

但是如果我没记错的话,我遇到了关于rspec模拟和存根后的多态行为和/或问题的问题,所以我放弃了这种方法。

我很感激任何指导。我已经多次前往谷歌寻找答案,但到目前为止,我所看到的一切似乎都没有直接适用。

更新

根据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

1 个答案:

答案 0 :(得分:0)

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

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

has_subscription

  • 查找班级名称(User
  • has_many / has_one / belongs_to关联添加到User
  • 将特殊关联添加到Billing::Subscriptionbelongs_to :user, ...