【问题标题】:How can you set up a multi-tenant Rails app without using subdomains?如何在不使用子域的情况下设置多租户 Rails 应用程序?
【发布时间】:2019-02-13 17:58:33
【问题描述】:

我正在尝试为员工创建一个带有后端的 SAAS 电子商务工具,该工具还允许客户在前端拥有帐户和结帐。我正在为如何设计这一点而苦苦挣扎,以便公司、帐户所有者、员工和客户都孤立于每个公司,同时还根据他们的角色有适当的限制。

据我目前阅读的内容来看,大多数 Rails 解决方案都使用带有子域的多租户模式(例如 Apartment gem)来隔离帐户。但是让您的网站使用一个大型应用程序和数据库似乎更简单。例如,Basecamp 最近使用Basecamp3 切换到这种方法。较新的应用似乎是这样构建的。

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

我找到了 this blog post,它解释了如何使用 Pundit 执行此类操作,但我仍然无法理解如何在同一个应用程序中与帐户所有者、员工和客户一起使用.

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

用户角色

  • 帐户所有者(创建公司帐户并拥有对其公司数据的完全访问权限)
  • 员工(受邀加入公司,但无权访问公司的某些数据,例如帐单信息)
  • 客户(可以注册网站并查看产品,将它们添加到购物车,但无法访问任何员工或帐户所有者功能。)
  • 所有用户(无论角色)都属于一个公司,不能访问另一个公司的数据。 (因此提供了在同一个应用上运行不同商店的能力,这是作为 SAAS 应用运行所必需的。)
  • 帐户所有者和员工可以 CRUD 产品,但不能对客户。

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

潜在的模型和关联

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

User
belongs_to :company

Product
belongs_to :company

授权

  • 是否可以使用 Pundit 根据用户角色限制控制器操作,然后通过模型关联确保数据被隔离?

注册流程

我对如何处理不同用户角色的范围以及“员工邀请”和“客户”注册可以适应注册流程的位置有点模糊。

这种方法行得通吗?

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

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

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

【问题讨论】:

    标签: ruby-on-rails ruby authorization multi-tenant pundit


    【解决方案1】:

    您以simple e-commerce site 开头,但您提出的问题表明您正在寻找更复杂的东西:) 您走在正确的轨道上。

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

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

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

    根据工作量的不同,使用子域可能是一项未实现的工作,除非您需要实际使用子域来达到虚荣目的(my.example.com 与 example.com/my),否则您可以在没有它的情况下进行多租户。

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

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

    我有一个项目,我正在做您所说的事情(专家限制数据,acts_as_tenant 存储事物),但随着它的发展,出现了某些模式,导致我走上了不同的道路。例如,命名空间管理员,而不是在同一控制器内进行管理员检查;因为如果你重写一个 API,你最终会试图让同一个端点做不同的事情,在我看来,将两个端点分开一个命名空间并记录实际行为会更干净。

    【讨论】:

    • 谢谢!这正是我需要的正确方向。这篇关于acts_as_tenant gem 的博文解释了很多 - confreaks.tv/videos/…。欣赏指点。还更新了问题,不将其称为“简单的电子商务应用程序”。至于命名空间,我想像这样:产品控制器 CRUD 仅适用于管理员,然后创建一个“店面”控制器用于向客户展示这些产品。你是这个意思吗?而不是将所有这些逻辑都放在产品上?
    • 我在想象 DHH 如何描述 basecamp 3 的名称间距,它由许多小控制器组成,几乎就像微服务一样。
    • 是的,就是这样。当你试图让一个控制器做不同的事情时,它会变得非常笨拙。一些简单的事情,例如“管理员可以代表其他人的 Foo”,在其中设置 creator_id 不仅在视图中变得复杂,而且在控制器、专家等都在同一个控制器中时变得复杂。相反,只需创建 2 个 foo 控制器;一个命名空间在 admin 下,逻辑更清晰地分离(恕我直言可读)。它的代码更多,但也更具可读性
    • 另外,您可能会看到:codementor.io/tips/8132473431/… 您可以使用 rails 路由约束来限制谁可以访问特定路由/命名空间路由。这可能是一个很好的开始方式。另外,我会说,有些人尝试将他们的不同用户分成表(用户、管理员等)是很常见的,但我认为最容易管理的是用户表中的所有用户,并带有某种类型的布尔值为角色标记,或使用 Rolify(如果您需要多角色支持)
    • 欣赏杰伊的所有建议。
    猜你喜欢
    • 2017-05-26
    • 1970-01-01
    • 2016-05-31
    • 1970-01-01
    • 2021-08-08
    • 1970-01-01
    • 1970-01-01
    • 2021-04-04
    • 1970-01-01
    相关资源
    最近更新 更多