为单个数据库多个应用程序建模用户表

问题描述 投票:1回答:1

假设我们有3个不同的应用程序 - serviceapp,subscriptionapp,ecomapp,所有应用程序都使用ruby on rails编写,并在后端使用相同的数据库,后端使用相同的数据库。因此,所有这三个应用程序的用户表都是相同的。如果用户是使用相同电子邮件和凭据的serviceapp的一部分,则他可以登录到subscriptionapp或ecomapp,反之亦然。

为所有应用程序选择相同的用户表和其他表的原因是纯粹的业务视角 - 相同的单个crm和售票系统用于销售和cdm团队跟踪所有内容。 Devise正在所有三个应用程序中与LDAP一起使用,因此登录和注册工作正常,没有任何问题。

问题:

直到现在用户的last_login_at是一个列,所以我们真的无法分辨他上次登录的应用程序。但是现在我们必须分别开始记录这些细节,比如他最后一次登录serviceapp,ecomapp,订阅app separetly。

此外,我们开始使用一个特定应用程序的新crm - subscriptionapp和该特定应用程序的客户端(用户),我们必须存储额外的信息,如来自crm的unq_id等等。

我的初步想法是在用户表本身中添加这些列。但是在将来,我们可能会向用户表添加一些特定于应用程序的额外信息。因此,将其添加到主用户表中不是一个好主意。在这种情况下我该如何处理?我创建了三个不同的表,例如subscriptionapp_client,ecomapp_client,serviceapp_client已经将它们与用户表关联起来,例如用户has_one *** _ client。

如果关联存在,就像user.subscriptionapp_client.present?他是该应用程序的客户端,我们可以存储最后一次登录,crm_uniq_id以及该表中的所有内容。

还有其他可能适合这个问题的好方法吗?我正在阅读有关MTI的内容,但看起来它无法解决问题。

ruby-on-rails ruby database-design data-modeling
1个回答
0
投票

使用JSON的单表继承。

class CreateClientAccount < ActiveRecord::Migration[5.2]
  def change
    create_table :client_accounts do |t|
      t.references :user
      t.string :uid # the unique id on the client application
      t.string :type
      t.integer :sign_in_count
      t.datetime :last_sign_in_at
      t.jsonb :metadata
      t.timestamps
    end
    add_index :client_accounts, [:user_id, :type], unique: true
  end
end

class User
  has_many :client_accounts
  has_one :service_account, class_name: 'ServiceApp::ClientAccount'
  # ...
end

class ClientAccount < ApplicationRecord
  belongs_to :user
  validates_uniqueness_of :user_id, scope: :type
end

module ServiceApp
  class ClientAccount < ::ClientAccount
  end
end

module SubscriptionApp
  class ClientAccount < ::ClientAccount
  end
end

module EcomApp
  class ClientAccount < ::ClientAccount
  end
end

这样可以避免在架构中维护X数量表时非常缺乏吸引力的重复,而JSONB列仍然为您提供了大量的灵活性。然而,它在很多方面只是对EAV pattern的升级。

它与MTI有很多共同之处。在MTI中,您将使用与另一个表的关联,该表填充与JSON列相同的目的 - 使关系模型更灵活。这可以是多态的,也可以为每种特定类型提供X个外键。

每种类型一张表。

class User < ApplicationRecord
  has_one :subscription_account
  has_one :service_account 
  # ...
end

class ClientAccount < ApplicationModel
  self.abstract_class = true 
  belongs_to :user
end

class SubscriptionAccount < ClientAccount
end

class ServiceAccount < ClientAccount
end

# ...

这是最灵活的选项,但如果要添加功能,则必须为每个表创建迁移。这也意味着如果您想要所有类型,则无法查询单个同源集合。您必须执行X个连接。

除非每种类型的要求大不相同,否则这并不是那么吸引人。

© www.soinside.com 2019 - 2024. All rights reserved.