在rails中管理数据库的两个快照

时间:2013-06-10 15:15:25

标签: ruby-on-rails activerecord snapshot

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

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

我们有什么方法可以将实时数据(由应用程序提取)与用户可以在CRUD中修改的数据分开?我们可以使用DBMS功能,还是宝石?

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

编辑:我们决定在此期间使用文件系统缓存,为每个人提供非最新版本的内容。然后,当一切都好的时候我们继续失效,这样每个人都可以拥有最新的版本。但我不认为这是一个可靠的解决方案......

Edit2:这个问题的全部目的是我们想要控制移动应用程序读取的内容,某种审核。我们希望能够基本管理变更和不同的状态/版本/快照。

4 个答案:

答案 0 :(得分: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,而WRITE转到另一个实例URL。

    (OR)

  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
    
  3. 这将根据请求方法在production_readproduction配置之间切换。您也可以订购before_filter,以便在您的身份验证和授权之后仅在之后进行切换,最后它在您的控制器逻辑之前发生。

    有时也需要对所有模型类执行相同的establish_connection。因此,在这种情况下,您只需遍历ActiveRecord::Base子类并调用相同的establish_connection逻辑。哎呀,你甚至可以在切换连接之前省略一些子类!

    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 ...
    

答案 1 :(得分:0)

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

这听起来像是一个消息传递系统可以帮到你。

类似的东西:

+-----------+            +------------+
|           |            |            |
|           |            |            |
|  ProdDb   |            |  UserDB    |<--------- Content
|           |            |            |
|           |            |            |
+-----------+            +------------+
     ^                          +
     |                          |
     |                          |
     |                          |
     |        +-----------+     |
     |        | RabbitMQ  |     |
     +-------+|           |<----+
              |           |
              |           |
              |           |
              |-----------|
              |    Q1     |
              +-----------+
  1. 用户将数据写入所谓的UserDB
  2. 然后将数据发布到邮件系统中的邮件队列Q 1(我建议RabbitMQ
  3. 然后,工作人员使用用户数据读取下一个队列消息并对其进行验证,如果可以,则移动prodDB进行写入。

答案 2 :(得分:0)

vestal_versions宝石或paper_trail宝石可以帮到你。关于它们有很棒的Railscasts剧集:

答案 3 :(得分:0)

查看高级问题描述,这让我觉得数据库视图可能就是您所需要的。或许更敏捷的解决方案可能是较低特权的用户。

然后,您可以让非CRUD用户通过单独的Rails模型获取数据,该模型连接到另一个较低特权的数据库连接。 Rails 3 can do this easily.问题的大部分都在您的数据库中。基本上使用“仅选择权限”设置数据库。

底线是你应该能够在数据库级别解决这个问题,并在Rails级别上容纳它。