Rails - 多租户应用程序和定制框架

3
我正在使用单一代码库/应用程序组织一个多租户应用程序,使用子域名来检测租户,然后在Postgres上运行SET SCHEMA来完成有趣的事情。
我的问题是,某些客户将需要对主代码库进行各种级别的定制。 不算太多,但肯定足以让我不想通过添加大量if语句来开始破坏主模型和控制器。
使用视图加载路径覆盖视图很容易... 但我的问题是:如何为覆盖或添加功能到基本控制器、模型和助手提供一个良好的框架,以根据需要调整每个租户的内容? 理想情况下,它应该非常无缝,并且不会侵入主要代码,并且应该提供一个良好的机制来组织定制代码。
我已经调查了一些选项,包括使用includes/extends(混合)。问题在于,在生产中,方法留在对象中(可以理解)。 我尝试过mixology gem来解决这个问题,但它并没有完全按照我的意图工作,而且比我想象的更具侵入性,我也不清楚如何将其与模型相关联(在控制器中,我只是尝试通过before/after过滤器进行混合/取消混合)。
如果有人对如何最好地解决这个问题有任何想法,我将非常感激您的反馈。顺便说一句,这是Rails3。

相关问题在这里。好奇想知道你是否已经解决了它。 - Denis de Bernardy
2个回答

0

如果你想在请求之间动态切换数据库,那么我认为你会遇到很多麻烦,至少在使用ActiveRecord时是这样的。这将严重破坏缓存系统,因为它是基于ID而不是ID + Schema来记忆事物的,这可能导致交叉污染。

从架构角度来看,通常最好在内部分区数据库,并相应地对每个记录进行范围限制。例如:

class Site < ActiveRecord::Base
  # Represents a site or installation of the application
end

class User < ActiveRecord::Base
  belongs_to :site
end

将所有内容链接到主要的Site记录,或者使用最能描述您用于分区的方法。保持一致的范围比切换模式容易得多。
如果出于扩展的原因,您想在未来拆分数据库,如果您小心地标记了所有站点相关记录的一致的site_id列,您可以轻松地将所有这些记录转置到新数据库中。

Tadman,谢谢你的回复。数据库并不是真正的问题,交叉污染也不是。我不会在运行时切换数据库,我将使用Postgres的模式功能,并通过一个环绕过滤器选择模式,这应该没问题。而且由于我不是多线程的,所以应该没有交叉污染的问题。你实际上可以通过Morph Labs的Guy Naor在acts_as_conference 2009中的证明来看到这一点:http://www.bestechvideos.com/2009/03/26/acts_as_conference-2009-writing-multi-tenant-applications-in-rails。我的问题更多与定制功能相关。 - Mike Scappa
由于各种原因,包括但不限于安全性,在共享表中对site_id进行作用域限定并不可行。我认为这种方法更容易出现“错误”,导致交叉污染的情况比PostgreSQL的模式更多。 - Mike Scappa
最可靠的方法是使用单独的部署,并为每个实例使用不同的'database.yml'文件,如果通过类似于Passenger的负载平衡前端进行管理,则并不像听起来那么糟糕。也许在这方面我更加老派。我会看一下那个视频。 - tadman
2
问题不在于数据。此外,通过不同的数据库分离数据并不理想。这将要求我在客户端级别上管理实例,这将很难适当地扩展(有些客户很热门,有些则不是等等)。关于数据,在我的情况下,最有效的方法是使用pg模式。正如我所指出的,我的问题特别涉及为每个客户定制。这意味着对控制器、模型和视图进行修改(在租户级别上覆盖默认MVC而不创建完全独立的应用程序)。 - Mike Scappa
我想我和你一样好奇,想知道这个问题的答案。 - tadman

0

一个钩子+插件的设置能否满足您的需求?例如:将额外的功能构建到另一个模型中,在您需要修改的任何操作上检查钩子表以查看用户是否需要任何额外的操作,钩子表还指定了要执行的操作,因此您可以轻松地为不同的用户设置不同的配置。

如果您发现更好的答案,请更新。


实际上,这与我最终采取的方法非常相似。代码需要进行优化,但似乎是有效的。基本上,我在数据库中为一个类定义新的方法(包括方法的代码),或者重新定义数据库中的方法。在运行时,它会检查给定上下文是否存在修订后的操作或新的操作,并运行评估代码。对于重新定义的操作,我会创建一个指向旧操作的别名,然后在请求完成时取消别名——这在单线程环境中应该可以正常工作。 - Mike Scappa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接