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:
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
source share