Use Readyset with Ruby on Rails

This guide walks you through how to use Readyset with your Ruby on Rails app. To do this, you'll use the built-in Rails multiple database support (opens in a new tab) to get the performance of caching with the simplicity of a single read replica.

0. Set up Readyset

First, you'll set up Readyset using Docker.

  1. Make sure your database is configured for Readyset
  2. Install Readyset

1. Configure Rails in three steps

Ruby On Rails allows you to configure Readyset as a read replica and define a time window after writes for when to switch read traffic over to Readyset. This allows clients to observe recent writes if there is write traffic ongoing while still taking advantage of Readyset's caching for read-heavy workloads.

This will take three steps. You'll need to add Readyset as a read replica, then configure ActiveRecord to route traffic, and finally configure Rails' connection switching middleware with a few quick changes.

a. Update database configuration

Taking advantage of Readyset means defining a read replica of your primary database. Rails makes this incredibly simple and in the case of Readyset, you'll configure the replica to point to your Readyset instance. We recommend following Rails established patterns and name your primary database as primary and then your read replica Readyset instance as primary_replica.

For instance, your database.yml file will look something like this:

production:
  primary:
    database: my_primary_database
    username: root
    password: <%= ENV['ROOT_PASSWORD'] %>
    adapter: postgresql
  primary_replica:
    database: my_primary_database
    username: root
    password: <%= ENV['READYSET_PASSWORD'] %>
    host: <%= ENV['READYSET_HOST'] %>
    port: 5433
    adapter: postgresql
    replica: true 
    database_tasks: false

It's important to note that the primary_replica definition points to Readyset and that two flags are set: replica is true and database_tasks is false. The database_tasks flag will disable Rails database migrations running against Readyset. This isn't needed as Readyset will see any changes to the primary database already.

b. Update ApplicationRecord to use two connections

In your application's app/models directory, you'll find a base class for all of your model classes often called ApplicationRecord. Open up that class and add the following line:

connects_to database: { writing: :primary, reading: :primary_replica }

If you haven't made any changes to this base class, it should look like this:

class ApplicationRecord < ActiveRecord::Base
  primary_abstract_class 
 
  connects_to database: { writing: :primary, reading: :primary_replica }
end

Note how connects_to database: is pointing to the names of both the primary database and Readyset via the names you defined in your database.yml configuration.

If you aren't on Rails 7, you'll need to replace primary_abstract_class with self.abstract_class = true. What's more, if for some reason you do not have access to an ApplicationRecord base class, you'll need to monkey patch (opens in a new tab) one.

c. Activate connection switching middleware

Finally, you'll need to activate Rails middleware that'll ensure writes go to the primary database and reads through Readyset. First run this command to generate a configuration file:

bin/rails generate active_record:multi_db

This command will create a new file: config/initializers/multi_db.rb. Open up that file and uncomment the following lines:

Rails.application.configure do
  config.active_record.database_selector = { delay: 2.seconds }
  config.active_record.database_resolver = ActiveRecord::Middleware::DatabaseSelector::Resolver
  config.active_record.database_resolver_context = ActiveRecord::Middleware::DatabaseSelector::Resolver::Session
end

It's important to note that a delay of 2 seconds is designed to ensure the read replica (in this case Readyset) is consistent with writes that are going directly to the primary database.

You're off to the races!

At this point, if you start your Rails application, read requests will go directly to Readyset and writes will go to your primary Postgres database. You'll next need to configure which SQL select statements (i.e. reads) you’ll want to cache. Check out our caching guide for more information.