如果我理解正确,这是你的问题:
- 单个 Rails 应用程序处理来自移动应用程序的 READ 和 WRITE 请求
- 您希望单个 Rails 应用程序使用不同的 READ 数据库和 WRITE 数据库
- 并且您希望能够在 WRITE 传播到 READ DB 时进行自定义控制
解决问题的最简洁方法是:
创建两个数据库(我们称它们为 READ DB 和 WRITE DB),并在它们之间设置主/从复制。因此,无论您在 WRITE DB 中进行什么查询,它都会在 READ DB 中复制,并且您可以控制何时以及如何触发该复制。几乎每个数据库都支持这种开箱即用的方式。这是MySQL的说明。您甚至不必为此切换到 PostgreSQL,因为 Mater/Slave 复制在任何一个上都是标准且健壮的。
对于 Rails 应用程序,您现在将在以下位置配置两个数据库config/database/yml
:
production:
# configuration for your WRITE DB
adapter: mysql
database: ...
host: ...
username: ...
password: ...
production_read:
# configuration for your READ DB
adapter: mysql
database: ...
host: ...
username: ...
password: ...
然后你有两个选择:
部署两个相同的实例。代码没有变化,只是部署了两个实例,一个RAILS_ENV=production_read
用于 READ 的实例,另一个RAILS_ENV=production
用于 WRITE 的实例。更改您的移动应用程序,以便 READs 转到第一个实例 URL,而 WRITEs 转到另一个实例 URL。
(或者)
只运行一个 Rails 应用程序实例,只需在production
和production_read
数据库之间切换。由于您拥有适当的 Web 服务,我将假设您正在使用 GET 请求来读取数据。所有其他(POST/PUT/DELETE/etc)请求都是写请求。如果您不这样做,那么我首先建议您无论如何都要这样做。鉴于您使用 GET 进行读取,那么您将执行以下操作:
# app/controllers/application_controller.rb
class ApplicationController
before_filter do
# Switch to production_read or production configurations
# based on request method
if request.get?
ActiveRecord::Base.establish_connection "production_read"
else
ActiveRecord::Base.establish_connection "production"
end
end
这将根据请求方法在您的production_read
和配置之间切换。production
您还可以订购,before_filter
以便仅在您的身份验证和授权之后发生切换,最后它发生在您的控制器逻辑之前。
有时也需要establish_connection
对所有模型类执行相同的操作。因此,在这种情况下,您只需遍历ActiveRecord::Base
子类并调用相同的建立连接逻辑。哎呀,您甚至可以在切换连接之前省略一些子类!
ActiveRecord::Base.descendants.each do |model_class|
model_class.establish_connection (request.get? ? "production_read" : "production")
end
# Or let's say you want to switch all models *except* User/Session models to the READ DB
(ActiveRecord::Base.descendants - [User, Session]).each do ...