如何在不使用子域的情况下设置多租户 Rails 应用程序?

How can you set up a multi-tenant Rails app without using subdomains?

我正在尝试为员工创建一个 SAAS 电子商务工具,该工具还允许客户在前端拥有帐户和结账。我正在努力设计这个,以便公司、帐户所有者、员工和客户都与每个公司隔离,同时还根据他们的角色设置适当的限制。

到目前为止,据我所知,大多数 rails 解决方案都使用带有子域的多租户模式,例如 Apartment gem, to silo off accounts. But it seems simpler to just have your site use one big app and database. For instance Basecamp recently switched to this approach with Basecamp3。较新的应用程序似乎是以这种方式构建的。

而且,管理功能和客户帐户/前端商店应该完全是独立的应用程序,还是可以使用“majestic monolith”来实现?一个大的应用程序和数据库,虽然很大,但对我来说似乎更直接。

我找到了 this blog post that explains how to do something like this with Pundit,但我仍然无法全面了解这如何与同一个应用程序中的帐户所有者、员工和客户一起工作。

以下是我的应用程序的基本需求:

用户角色

一个很好的类比是 Shopify 的管理区域和客户帐户目前如何为店主工作,但与 Shopify 不同的是,它不需要使用子域。

潜在模型和关联

Company
has_many :users, dependent: :destroy
has_many :products, dependent: :destroy

User
belongs_to :company

Product
belongs_to :company

授权

注册流程

我不太清楚如何处理不同用户角色的范围界定,以及 "staff invites" 和 "customer" 注册适合注册流程的位置。

这种方法行得通吗?

  1. 为 "Account Owner Signup," "Staff Signup," "Customer Signup," 创建单独的控制器,然后将我的注册表单嵌入到这些视图中。 (使用 Clearance 进行身份验证,并希望尽可能保留它,但只根据需要增加它)。
  2. 帐户所有者注册:因此,如果有人通过新帐户注册控制器(带有嵌入式身份验证表单)注册,他们也会创建一个公司。
  3. 员工邀请:帐户所有者可以通过输入姓名和电子邮件地址来创建新的员工用户。这将创建一个角色为 "Staff" 的新用户(因此不能成为另一个帐户的帐户所有者)。新 "Staff" 用户会收到一封邀请电子邮件,基本上是密码重置电子邮件,邀请他们通过创建密码来接受邀请。
  4. 客户注册:如果有人通过 "Customer Signup" 控制器注册,他们将自动获得用户角色 "customer"。不确定在这种情况下如何设置公司 ID。 (将 company_id 作为客户注册表单的隐藏输入传递?)

是否有更好的方法来设计我所缺少的此类应用程序?我在正确的轨道上吗?我没有构建这样的东西的经验,所以任何线索都会非常有帮助。

似乎较新的应用程序遵循这种类型的多租户模式,而不是子域。

您用 simple e-commerce site 打开,但您提出的问题表明您正在寻找稍微复杂一点的东西 :) 您走在正确的轨道上。

acts_as_tenant gem值得一看。我们现在使用它,它有助于确保您的查询范围适当。

如果您需要扮演角色,我也会查看并评估 rolify(但也不排除您的用户的布尔标志)。

我不排除设计,但清关很受欢迎。

根据工作量,使用子域可能是未实现的工作,除非您出于虚荣目的实际使用子域(my.example.com 对比示例。com/my),您可以进行多项操作没有它的租赁。

如果不同角色的访问权限差异很大,我会考虑为不同的角色使用单独的控制器和命名空间;您还可以使用 Pundit 将它们组合成单个控制器(但这可能很笨重)。您仍然希望使用 Pundit,但是,Pundit 可以做一些事情,例如用户应该看到的记录范围。

您在正确的轨道上提出了正确的问题,但所有这些问题的答案将取决于其他问题(您现在可能甚至无法回答)。

我有一个项目,我正在做你提到的事情(专家限制数据,acts_as_tenant 到筒仓的东西)但随着它的发展,某些模式出现,导致我走上了不同的道路。命名空间管理,而不是在同一个控制器内进行管理检查;因为如果你重新写入 API 你最终会尝试让同一个端点做不同的事情,并且在我看来,将命名空间后面的 2 个端点分开并记录实际行为会更清晰。