Rails 6 introduced a new functionality to configure and manage multiple databases in our application.
The best examples for multiple database configuration are:
- Primary replica configuration, where all writes are executed on the primary and all reads on replica database.
- Application has multiple databases to deal with.
For e.g, we store
orders
of user in one database and theirarchived
orders in different database.
To set multiple databases in our Rails application we need to set our
database.yml
as below
Here, we have created two databases primary
and secondary
.
We have also added one replica to the primary
database.
The reads for primary
database will be performed from primary_database_replica
and writes from primary_database
.
But, for secondary
both reads and writes will be performed on
secondary_database
.
There can be cases when we want to block the writes on the database:
- While performing a read operation.
- While executing a code block or transaction.
Examples for this use case can be:
- Converting a database from a single DB to a primary/replica
setup.
As shown in the above example, if we try to split
secondary
database intosecondary_database
(for write operation) andsecondary_database_replica
(for read operation). - Switching between databases i.e., from primary to replica or replica to primary and want to make sure that writes are not performed on replica.
To tackle the above issue, Rails 6 added ability to block writes to a database, even if the database user has permission to write (the database is a primary and not a replica).
As per the above example, database user can perform write operation
(role: :writing
).
But, if we call while_preventing_writes
and try to create a User using
User.create!
, it will raise an exception.
If we are in read role
and call while_preventing_writes
, no error is raised
while running User.first
, since we are not writing.
Rails internally identifies whether a query is a read or write.
So, when SQL queries like INSERT
, UPDATE
are executed and writes are blocked
the ActiveRecord::StatementInvalid
error will be raised.