【问题标题】:Heroku follow : how to handle multiple databases in a Rails app?Heroku 关注:如何在 Rails 应用程序中处理多个数据库?
【发布时间】:2012-08-27 15:54:34
【问题描述】:

我们在 Heroku 上托管了一个 Rails 应用程序,我需要为我们的营销人员设置一些分析页面。这似乎是 Heroku follow database

的典型用例

这两个数据库将共享相同的模型类,我只想要一些操作来查询复制的数据库。

在我的应用中处理这种情况的首选方法是什么?

ActiveRecord::Base documentation 谈论特定类的连接:

您还可以设置特定于类的连接。例如,如果课程 是一个 ActiveRecord::Base,但驻留在不同的数据库中,您可以 只是说 Course.establish_connection 和 Course 及其所有 子类将改为使用此连接。

我应该对我的所有模型类进行子类化以指定与辅助数据库的连接吗? (它甚至会工作吗?)

我也找到了这个 gem,但它似乎不再维护了....magic_multi_connections gem ?

【问题讨论】:

  • 据我了解,这解释了如何访问存储在不同数据库中的不同模型。这不是相同的情况:我将有一个辅助数据库,它是主数据库的只读副本。如果我遵循这种方法,我将需要对我所有的模型类进行子类化......

标签: ruby-on-rails heroku multiple-databases


【解决方案1】:

所以...我喜欢这个解决方案:

module Analytics

  class Base < ActiveRecord::Base
    self.abstract_class = true
    establish_connection ENV['ANALYTICS_DATABASE_URL']
  end

  class User < Base; end

  class Product < Base; end

end

现在您的模型都连接到您的分析数据库(跟随者)。

如果您需要在分析应用和普通应用之间共享范围或方法,您可以将共享代码放在一个 mixin 中,然后将其包含在您的 Analytics 或普通模型中。

或者,您可以在控制器中用于分析的模型上调用.establish_connection,然后再将它们用于分析,但我不知道这是否会破坏您对其他正常网络请求的连接,需要您在下一个请求时将其设置回正常的数据库连接...

更新:我突然想到了另一个想法:

class UserBase < ActiveRecord::Base
  self.abstract_class = true
  # all your user model code goes here
end

class User < UserBase
  establish_connection(Rails.env) # connect to your normal database
end

class AnalyticsUser < UserBase
  self.table_name = 'users'
  establish_connection(ENV['ANALYTICS_DATABASE_URL'])
end

这允许您在模型之间共享所有代码,无论它们是用于分析还是正常的 Web 请求,但根据模型名称设置不同的连接。

另外,作为旁注,如果您不想在您的开发环境中设置追随者,只需在您的 development.rb 中设置 ENV['ANALYTICS_DATABASE_URL']:

ENV['ANALYTICS_DATABASE_URL'] ||= 'postgres://localhost/myapp_development'

显然,在 Heroku 上,您需要将 ANALYTICS_DATABASE_URL 的配置变量重命名或设置为关注者的任何 DATABASE_URL。

【讨论】:

  • 如果您这样做(UPDATE 中的那个),您将创建多个连接池,因为 Rails 每次调用“建立连接”方法时都会创建一个连接池。使用 UserBase 中的连接将其保留为第一次是一种更好的方法。
【解决方案2】:

为了更好地回答这个问题:Heroku 现在使用Octopus gem 发布了处理这种情况的“官方”方式:

https://devcenter.heroku.com/articles/distributing-reads-to-followers-with-octopus

使用这个 gem,可以创建一个完全复制的模型,或者只在跟随者上执行一个块:

Octopus.using(:slave_two) do
  User.create(:name => "Mike")
end

【讨论】:

    猜你喜欢
    • 2011-12-02
    • 2014-10-20
    • 1970-01-01
    • 1970-01-01
    • 2011-06-07
    • 1970-01-01
    • 1970-01-01
    • 2011-01-28
    • 1970-01-01
    相关资源
    最近更新 更多