production:
primary:
adapter: postgresql
url: <%= ENV['DATABASE_URL'] %>
pool: <%= ENV.fetch("RAILS_MAX_THREADS", 5) %>
primary_replica:
adapter: postgresql
url: <%= ENV['DATABASE_REPLICA_URL'] %>
pool: <%= ENV.fetch("RAILS_MAX_THREADS", 5) %>
replica: true
class ApplicationRecord < ActiveRecord::Base
primary_abstract_class
connects_to database: { writing: :primary, reading: :primary_replica }
end
module Api
module V1
class PostsController < BaseController
around_action :use_read_replica, only: [:index, :show]
def index
posts = Post.published.includes(:author).page(params[:page])
render json: posts
end
def create
# Automatically uses primary for writes
post = current_user.posts.create!(post_params)
render json: post, status: :created
end
private
def use_read_replica
ActiveRecord::Base.connected_to(role: :reading) do
yield
end
end
end
end
end
As applications grow, read operations often dominate database load. Directing reads to replica databases while keeping writes on the primary reduces contention and improves response times. Rails makes this straightforward with connects_to and role-based routing. I configure database.yml with separate connection pools for primary and replica, and use ActiveRecord::Base.connected_to(role: :reading) blocks to route queries to replicas. The framework automatically routes writes to primary regardless of the current role. For API endpoints that only read data, I set a controller-level around_action to use the reading role by default. Replica lag is a consideration—I use primaries for reads immediately after writes to avoid stale data.
Related snips
-- Simple function
CREATE OR REPLACE FUNCTION get_full_name(
first_name VARCHAR,
last_name VARCHAR
)
RETURNS VARCHAR AS $$
Stored procedures and functions in PostgreSQL
class CommentsController < ApplicationController
before_action :set_post
def create
@comment = @post.comments.build(comment_params)
System test: asserting Turbo Stream responses
class Post < ApplicationRecord
belongs_to :author, class_name: 'User'
has_many :comments, dependent: :destroy
scope :published, -> { where.not(published_at: nil).where('published_at <= ?', Time.current) }
scope :draft, -> { where(published_at: nil) }
ActiveRecord scopes for reusable query logic
module Api
module V1
class UsersController < BaseController
def show
user = User.includes(:profile).find(params[:id])
ETags for conditional requests and caching
class PostsController < ApplicationController
def index
@posts = Post.includes(:author)
.order(created_at: :desc)
.page(params[:page])
.per(10)
Turbo Frames: infinite scroll with lazy-loading frame
require "csv"
class PeopleCsvStream
include Enumerable
HEADERS = %w[id full_name email signed_up_at plan].freeze
Resilient CSV Export as a Streamed Response
Share this code
Here's the card — post it anywhere.