在Rails中设计多租户应用

时间:2017-09-13 23:59:58

标签: ruby-on-rails ruby-on-rails-5 multi-tenant

我正在使用Rails实现多租户应用。我的方法是不使用postgres内置的多租户功能并添加一列来记录子域。这就是问题所在:)

让我们来看看这个例子

class Organisation < ActiveRecord::Base
  has_many :users
end

class User < ActiveRecord::Base
  belongs_to :organisation
end

我在考虑两种方法:

方法1

仅向subdomain

添加organisations
  • 专业 - 关系数据库的工作方式\ 0 /
  • 缺点 - 当我有更复杂的查询时,这将使我的代码变慢

方法2

subdomainorganisations

添加users
  • 专业人士 - 这将使查询更快
  • 缺点 - 我反对关系数据库

所以问题是,我应该在上面两种方法之间采用什么样的方法,还是有一种我没有想到的不同方法?

2 个答案:

答案 0 :(得分:1)

我的意见将是第一步,有几个原因

  1. 使用随activerecord +范围提供的关系数据库将使编写软件更容易,如果您稍后在组织下有更多对象,例如事务,项目(在用户旁边),
  2. 我有一个具有多租户功能的项目,下面是我项目中的设计样本

    class Company < ApplicationRecord
        has_many :users     
      # transaction
        has_many :transactions
        has_many :journals , :through => :transactions
      # item
        has_many :items
        # other has_many ...
    end
    

    并且在控制器中,您可以使用预先加载来最小化查询(包括/加入)

    @company.includes(:users).scope_filter_here.search(params[:q])
    
      与方法编号2相比,
    1. 方法1更方便用户使用,因为用户编写网址时更简单,输入的网址越少(个人意见)。

答案 1 :(得分:1)

我们运行一个多租户Rails应用程序,只有少于500个表支持的类,如果我不得不猜测我会说其中大约400个与客户端数据有关。

特定于客户端的属性保存在Client模型中,但我们将client_id添加到数据库上具有非空约束的每个客户端表。只有少数人被编入索引,但因为他们通常只能通过父记录访问。

我们不必担心设置客户端ID,因为模型通常会:

class Child

  after_initialize do
    self.client ||= parent.client
  end

end

我们将client_id添加到许多表中,因为我们有很多代码可以执行:

@books = current_user.client.books

...因此,在这些情况下,我们会直接从Client与模型建立关联,并对client_id编制索引。

我们将client_id添加到所有表中,因为出于操作或不寻常的原因,我们经常希望能够找到客户的所有相关记录...

MarketingText.where(client: Client.snowbooks).group(:type).count

......并且必须通过父记录才不方便。

另外,因为我们决定在所有特定于客户的表上执行此操作,所以我们不必对每个表做出决定。

为了解决您的问题,我要做的是仅将子域添加到Organisation。但是,我会将organisation_id列添加到每个包含特定于组织的数据的表中。

如果你有很多客户但是你将会普遍熟悉他们的子域名,那么我会在组织上编写一个允许你使用的元程序方法:

Organisation.some_subdomain

...获取所需的组织,然后直接从组织模型中找到具有关联的子记录(在任何表中)...

Organisation.some_subdomain.users
Organisation.some_subdomain.prices
Organisation.some_subdomain.whatevers