Rails 6 adds ability to block writes to a database

2 minute read

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 their archived orders in different database.

To set multiple databases in our Rails application we need to set our database.yml as below

development: primary: << : * default database: primary_database primary_replica: << : * default database: primary_database_replica replica: true secondary: << : * default database: secondary_database

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 into secondary_database (for write operation) and secondary_database_replica (for read operation).

database into (for write operation) and (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).

ActiveRecord :: Base . connected_to ( role: :writing ) do User . connection . while_preventing_writes do # will raise because we're blocking writes User . create! end end ActiveRecord :: Base . connected_to ( role: :reading ) do User . connection . while_preventing_writes do # will not raise because we're not writing User . first end end

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.