Rails Web API 中的单模式多租户
Single schema multi tenancy in a Rails Web API
我有一个客户端应用程序 - Angular JS 前端和一个 Rails API 后端以及一个 MySQL 数据库。我正在尝试将应用程序转换为单一架构多租户应用程序。我读了很多书,并且:
- 如果可能,我不想使用 gem - 公寓,它是多个模式并使用 Postgres 不符合要求,act_as_tenant 似乎使用 Thread.current识别我不想做的租户。
- 我读到 default_scope 也不应该使用,出于多种原因,我不会在这里展开。
我将请求 header 中的租户令牌从前端传递到 Rails 后端,并使用租户令牌在我的 ApplicationController 中识别租户。我现在正在找出读取和写入数据的最佳方法,以便与发出请求的租户相关联。
排除了上述选项后,我能看到的唯一选项是进入我的所有控制器方法并在写入和读取数据的任何地方更新它们。我更愿意对我的每个模型应用某种回调,以便在写入数据时始终写入租户 ID,并且在读取数据时始终将租户 ID 用作过滤器。
鉴于我无法访问模型中的租户令牌,除了更新我的所有控制器方法之外,我不确定如何继续此操作,这将是一个艰巨且容易出错的过程。
提前致谢!
不使用 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
我有一个客户端应用程序 - Angular JS 前端和一个 Rails API 后端以及一个 MySQL 数据库。我正在尝试将应用程序转换为单一架构多租户应用程序。我读了很多书,并且:
- 如果可能,我不想使用 gem - 公寓,它是多个模式并使用 Postgres 不符合要求,act_as_tenant 似乎使用 Thread.current识别我不想做的租户。
- 我读到 default_scope 也不应该使用,出于多种原因,我不会在这里展开。
我将请求 header 中的租户令牌从前端传递到 Rails 后端,并使用租户令牌在我的 ApplicationController 中识别租户。我现在正在找出读取和写入数据的最佳方法,以便与发出请求的租户相关联。
排除了上述选项后,我能看到的唯一选项是进入我的所有控制器方法并在写入和读取数据的任何地方更新它们。我更愿意对我的每个模型应用某种回调,以便在写入数据时始终写入租户 ID,并且在读取数据时始终将租户 ID 用作过滤器。
鉴于我无法访问模型中的租户令牌,除了更新我的所有控制器方法之外,我不确定如何继续此操作,这将是一个艰巨且容易出错的过程。
提前致谢!
不使用 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