Rails Web API中的单一模式多租户

时间:2016-11-24 02:07:43

标签: mysql ruby-on-rails ruby schema multi-tenant

我有一个客户端应用程序 - Angular JS前端和带有MySQL DB的Rails API后端。我正在尝试将应用程序转换为单个架构多租户应用程序。我做了很多阅读并且:

  • 我不想在可能的情况下使用gem - Apartment,它是多个模式并使用Postgres不适合账单,而act_as_tenant似乎使用Thread.current来识别我不想做的租户。
  • 我已经读过不应该使用default_scope,原因很多,我不会进入这里。

我将请求标头中的租户令牌从前端传递到Rails后端,并使用租户令牌识别我的ApplicationController中的租户。我现在正在找出读取和写入数据的最佳方法,以便与发出请求的租户相关联。

排除了上述选项之后,我能看到的唯一选择是进入我的所有控制器方法,并在数据写入和读取的任何地方更新它们。我宁愿对我的每个模型应用某种回调,以便在写入数据时始终写入租户ID,并且只要读取数据,租户ID就总是用作过滤器。

鉴于我无法访问模型中的租户令牌,我不知道除了更新我的所有控制器方法之外如何继续进行此操作,这将是一个艰巨且容易出错的过程。

提前致谢!

1 个答案:

答案 0 :(得分:0)

不使用default_scope是一个好主意 - 它表现为一种黑盒子,并且可以破坏线路,特别是如果你做任何偏执删除的事情。

执行所提问题的一种方法是使用thread_mattr_accessor。您可以在Web请求开始时定义tenant_id标记,然后在Web请求期间通过class属性访问它。这将在您的租户模型上创建一个线程安全的属性访问器。

在您的控制器中,您可以检测当前请求的租户(使用子域或令牌)并设置Token.current_id变量。此变量将在请求期间可用。请注意,它不会自动用于任何后台作业或其他进程,因为该变量是在当前线程内设置的。

使用this RailsCast中的范围演示了此方法,但您不必使用范围。您可以设置一个辅助方法,例如current_tenant,然后明确指出所有查询,例如current_tenant.posts

# models/tenant.rb
class Tenant < ApplicationRecord
  thread_cattr_accessor :current_id
  # ...
end

# controllers/application_controller.rb
class ApplicationController < ActionController::Base

  around_action :scope_current_tenant
  private def scope_current_tenant
    Tenant.current_id = current_tenant.id
    yield
  ensure
    Tenant.current_id = nil
  end

  def current_tenant
    @current_tenant ||= Tenant.find_by_token! params[:token]
  end

  helper_method :current_tenant
end