Manage two database snapshots on rails

We currently have a rails application (mainly CRUD) that is used as a web service for a mobile application.

At the moment, when users change content in the application, real-time changes are transferred to the mobile application because they use the same database.

Is there any way to establish a separation between the current data (selected by the application) and the data that users can change in CRUD? Is there a DBMS function we can use for this, or a gem?

We currently use MySQL, but we are actively looking for alternatives (e.g. Postgresql).

Edit: We decided to use the file system cache in the meantime to serve the latest version of content for everyone. Then we move on to invalidation when everything is in order, so that each can have the latest version. But I do not think this is a reliable solution ...

Edit2: The whole purpose of this question is that we want to have some control over what is read by the mobile application, something like moderation. We want to be able to manage changes and various states / versions / snapshots basically.

+4
source share
4 answers

If I understand correctly, this is your problem:

  • One Rails application processes READ and WRITE requests from a mobile application.
  • You want a single Rails application to use different READ and WRITE Database
  • And you want to have custom control when WRITEs are distributed in READ DB

The cleanest way to solve your problem:

Create two databases (call them READ DB and WRITE DB) and configure Master / Slave replication between them. Thus, any query that you make in a WRITE database is replicated to READ DB, and you can control when and how this replication starts. Almost every database supports this finished product. The following are MySQL instructions. You don’t even have to switch to PostgreSQL, because Mater / Slave replication is standard and reliable.

For a Rails application, you now configure two databases in 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: ... 

And then you have two options:

  • Expand two instances of the same. There are no changes in the code, but just deploy two instances, one with RAILS_ENV=production_read for READ and the other with RAILS_ENV=production for WRITE. Modify your mobile application so that READs fall into the URL of the first instance, and WRITE files go to a different URL of the instance.

    (OR)

  • Have only one instance of the Rails application and just switch between the production and production_read databases. Since you have a proper web service, I'm going to assume that you are using GET requests to read data. All other requests (POST / PUT / DELETE / etc) are write requests. If you do not do this, I first suggest you do it anyway. Given that you are using GET for reading, you should do the following:

     # 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 

This will switch between production_read and production configurations depending on the request method. You can also order before_filter so that the switch happens only after your authentication and authorization, and finally, it happens just before your controller logic.

Sometimes it is also required to do the same establish_connection for all model classes. So in this case, you just skip the ActiveRecord::Base subclasses and call the same connection_setting logic. Heck, you could even omit some subclasses before switching connections!

 ActiveRecord::Base.descendants.each do |model_class| model_class.establish_connection (request.get? ? "production_read" : "production") end # Or let say you want to switch all models *except* User/Session models to the READ DB (ActiveRecord::Base.descendants - [User, Session]).each do ... 
+3
source

What you are looking for, if I understand your question correctly, is to separate the production db from user editable content and run some validation / invalidation method during synchronization.

It looks like a messaging system would do the trick for you.

Sort of:

 +-----------+ +------------+ | | | | | | | | | ProdDb | | UserDB |<--------- Content | | | | | | | | +-----------+ +------------+ ^ + | | | | | | | +-----------+ | | | RabbitMQ | | +-------+| |<----+ | | | | | | |-----------| | Q1 | +-----------+ 
  • Users write data to the so-called UserDB
  • Then the data is sent to the Q 1 message queue in the messaging system (I recommend RabbitMQ
  • Then the worker then reads the next queue message with the user data and checks it, if he is okay - he moves prodDB for writing.
0
source

vestal_versions gem or paper_trail gem can help you. There are great episodes of Railscasts:

0
source

If you look at the description of the problem with a high level, it makes me think that perhaps presenting the database is what you need. Or perhaps a more flexible solution would be a lower user.

You can then use non-CRUD users to collect data through a separate Rails model that connects to another connection with a lower privileged database. Rails 3 can do this easily. The main part of the problem will be in your database. Essentially creating a database with Select only privileges.

On the bottom line, you should be able to solve this problem at the database level and place it at the Rails level.

0
source

Source: https://habr.com/ru/post/1485457/


All Articles