从应用程序控制器中优雅地从rails应用程序自动切换数据库?

时间:2010-03-24 18:17:38

标签: ruby-on-rails ruby

我已经看过几次这篇文章,但还没有真正找到这个具体问题的答案。

我想运行基于检测到的request.host的rails应用程序(想象我有两个子域指向相同的rails应用程序和服务器IP地址:myapp1.domain.com和myapp2.domain.com)。

我正在尝试让myapp1使用默认的“production”数据库,而myapp2请求总是使用备用远程数据库。以下是我在Application控制器中尝试执行的操作示例:

class ApplicationController < ActionController::Base
  helper :all 
  before_filter :use_alternate_db

  private

    def use_alternate_db

      if  request.host == 'myapp1.domain.com'
        regular_db
      elsif request.host == 'myapp2.domain.com'
        alternate_db
      end

    end

    def regular_db
      ActiveRecord::Base.establish_connection :production
    end

    def alternate_db
      ActiveRecord::Base.establish_connection(
      :adapter => 'mysql',
      :host => '...',
      :username => '...',
      :password => '...',
      :database => 'alternatedb'
      )

    end
end

问题是当它使用此方法切换数据库时,所有连接(包括跨不同子域的有效会话都会中断......)。在线的所有示例都有人在模型级别控制数据库连接,但这将涉及在我的应用程序中添加代码。有没有办法按照我上面建议的方式在每个请求的基础上全局切换数据库连接而不必在我的应用程序中注入代码?

这里增加的复杂性是我使用Heroku作为托管服务提供商,所以我无法控制apache / rails应用服务器级别。

我已经查看了像dbcharmer和magicmodels这样的解决方案,但似乎没有一个示例以我正在尝试的方式执行此操作。谢谢你的帮助!

1 个答案:

答案 0 :(得分:4)

我正在从你的问题中找出这一行:

  

所有连接(包括有效连接)   跨越不同的会议   子域名被中断......)。

听起来有些模型您希望连接到生产数据库,我猜您将这些模型存储在数据库中。看起来您希望会话与生产保持联系,其余的您希望切换到其他数据库。

您可以通过在ActiveRecord和您要更改的模型之间插入一个新类来更改连接。

这个类看起来像这样:

class MyAppModel < ActiveRecord::Base
  self.abstract_class = true
end

那么需要改变的模型应该继承它:

class User < MyAppModel
  #stuff
end

不应更改的模型应保持与ActiveRecord的连接。

最后,在ApplicationController中,改为在MyAppModel上调用establish_connection。

您可以根据需要使用尽可能多的类来执行此操作。 Model类将在heirarchy上向后工作,直到找到具有有效连接的第一个类,并使用它与数据库进行交互。不需要进行其他更改。