4

我们目前有一个用作移动应用程序的 Web 服务的 rails 应用程序(基本上是一个 CRUD)。

现在,当用户修改应用程序中的内容时,这些更改会在移动应用程序中生效,因为他们使用的是同一个数据库。

有什么方法可以将实时数据(由应用程序获取)和用户可以在 CRUD 中修改的数据分开?有没有我们可以使用的 DBMS 功能,或者 gem ?

我们目前正在使用 MySQL,但我们正在积极寻找替代品(例如 Postgresql)。

编辑:我们决定同时使用文件系统缓存,为每个人提供非最新版本的内容。然后,当一切正常时,我们会进行失效,以便每个人都可以拥有最新版本。但我不认为这是一个可靠的解决方案......

Edit2:这个问题的全部目的是我们希望对移动应用程序读取的内容有一些控制,某种适度。我们希望能够基本上管理更改和不同的状态/版本/快照。

4

4 回答 4

3

如果我理解正确,这是你的问题:

  • 单个 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: ...

然后你有两个选择:

  1. 部署两个相同的实例。代码没有变化,只是部署了两个实例,一个RAILS_ENV=production_read用于 READ 的实例,另一个RAILS_ENV=production用于 WRITE 的实例。更改您的移动应用程序,以便 READs 转到第一个实例 URL,而 WRITEs 转到另一个实例 URL。

    (或者)

  2. 只运行一个 Rails 应用程序实例,只需在productionproduction_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 ...
于 2013-06-15T17:05:23.400 回答
0

如果我的问题正确,您正在寻找的是将生产数据库与用户可编辑的内容分开,并在同步时运行一些验证/失效方法。

听起来消息系统会为您解决问题。

就像是:

+-----------+            +------------+
|           |            |            |
|           |            |            |
|  ProdDb   |            |  UserDB    |<--------- Content
|           |            |            |
|           |            |            |
+-----------+            +------------+
     ^                          +
     |                          |
     |                          |
     |                          |
     |        +-----------+     |
     |        | RabbitMQ  |     |
     +-------+|           |<----+
              |           |
              |           |
              |           |
              |-----------|
              |    Q1     |
              +-----------+
  1. 用户将数据写入所谓的 UserDB
  2. 然后将数据发布到Q消息系统中的消息队列 1(我推荐RabbitMQ
  3. 然后工作人员使用用户数据读取下一个队列消息并对其进行验证,如果没问题 - 它被移动以prodDB进行写入。
于 2013-06-13T08:20:56.737 回答
0

查看高级问题描述,这让我认为您可能需要一个数据库视图。或者,更灵活的解决方案可能是特权较低的用户。

然后,您可以让非 CRUD 用户通过单独的 Rails 模型获取数据,该模型连接到另一个较低权限的数据库连接。Rails 3 可以轻松做到这一点。大部分问题出在您的数据库中。本质上是使用 Select only 权限设置数据库。

底线是您应该能够在数据库级别解决这个问题并将其容纳在 Rails 级别。

于 2013-06-19T17:23:34.353 回答
0

vestal_versions gem 或paper_trail gem可以帮助您。有很多关于他们的 Railscasts 剧集:

于 2013-06-19T16:25:48.343 回答