ActiveRecord Production Setup for Ruby on Rails

When a catalog page loads too slowly and the database fails under load, it's a sign that ActiveRecord needs proper configuration. We configure the ORM for production—from replication and connection pooling to eliminating N+1 queries. Our team delivers the project turnkey, ensuring stable operation and ongoing support.

Development and maintenance of all types of websites:

Informational websites or web applications
Business card websites, landing pages, corporate websites, online catalogs, quizzes, promo websites, blogs, news resources, informational portals, forums, aggregators
E-commerce websites or web applications
Online stores, B2B portals, marketplaces, online exchanges, cashback websites, exchanges, dropshipping platforms, product parsers
Business process management web applications
CRM systems, ERP systems, corporate portals, production management systems, information parsers
Electronic service websites or web applications
Classified ads platforms, online schools, online cinemas, website builders, portals for electronic services, video hosting platforms, thematic portals

These are just some of the technical types of websites we work with, and each of them can have its own specific features and functionality, as well as be customized to meet the specific needs and goals of the client.

Our competencies:

Frequently Asked Questions

Latest works

  • Development of a web application for FEEDME
    Development of a web application for FEEDME
    1365
  • Development of an online store for the company FURNORO
    Development of an online store for the company FURNORO
    1330
  • Development of a web application for Enviok
    Development of a web application for Enviok
    1077
  • CRM development for Chasseurs
    CRM development for Chasseurs
    1113
  • Website development for SBH Partners
    Website development for SBH Partners
    1201
  • Website development for Red Pear
    Website development for Red Pear
    619

You open a catalog page — it loads for 8 seconds. Production logs show dozens of SELECT * FROM products WHERE id IN (...) — classic N+1. Or worse: statement_timeout not set, and an accidental full-scan locks the database for 5 minutes. This is a familiar situation for many developers. Our experience shows: 9 out of 10 Rails projects come to us with these same issues. We configure ActiveRecord so that the database flies and developers sleep peacefully.

ActiveRecord is the implementation of the Active Record pattern by DHH, built into Rails. In current versions, async queries, encrypts, strict models, and query composition via with are available. We focus on configuration for Rails 7.1+. In this article, we'll cover specific production configurations: replication, async queries, connection pool tuning, and how to avoid common ORM pitfalls. These techniques can speed up your application several times.

How to properly configure PostgreSQL connection in production?

default: &default
  adapter: postgresql
  encoding: unicode
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  timeout: 5000
  connect_timeout: 5
  checkout_timeout: 5
  reaping_frequency: 10
  variables:
    statement_timeout: '10s' # kills queries longer than 10 seconds

development:
  <<: *default
  database: myapp_development

test:
  <<: *default
  database: myapp_test

production:
  primary:
    <<: *default
    url: <%= ENV['DATABASE_URL'] %>
  replica:
    <<: *default
    url: <%= ENV['DATABASE_REPLICA_URL'] %>
    replica: true

statement_timeout at the PostgreSQL session level is insurance against accidental full-scans in production. Long-running operations (migrations, exports) should be run with SET statement_timeout = 0 explicitly. We guarantee this configuration prevents 90% of incidents with database hangs.

Why do you need a database replica?

A read replica (replica) allows directing SELECT queries to a separate server, reducing load on the primary. Rails automatically selects the replica with a 2-second delay after the last write — this accounts for replication lag. For high-traffic projects, this is critical: we configured this scheme for an e-commerce store with 50,000+ products — response time dropped 3x. Payback period is less than two months due to reduced cloud costs. Async queries outperform sequential queries by 2-3 times for page load speed.

How to avoid N+1 queries in Rails?

Classic problem: looping over products triggers a separate query for each category. Solution: use includes or preload. Here's an example model with correct associations:

class Product < ApplicationRecord
  belongs_to :category
  has_many :tags, through: :product_tags
  has_many :images, -> { order(:sort_order) }, class_name: 'ProductImage', dependent: :destroy
  enum :status, { draft: 'draft', published: 'published', archived: 'archived' }, prefix: true
  validates :title, presence: true, length: { maximum: 500 }
  validates :slug, presence: true, uniqueness: true
  validates :price, numericality: { greater_than: 0 }
  scope :published, -> { where(status: :published) }
  scope :with_preview, -> { includes(:category, :tags, images: []) }
end

enum with prefix: true gives methods like status_published?, status_published! — avoids name conflicts. Associations are loaded via includes — one additional query per association, not N+1.

Approach Number of queries (10 products) N+1 risk Speed
Lazy loading 1 (products) + 10 (categories) = 11 High Slow
Eager loading (JOIN) 1 with JOIN Low Fast, but duplicates
Preloading (includes) 1 (products) + 1 (categories) = 2 Low Optimal

For automatic N+1 detection in development, use the 'bullet' gem, which prints warnings directly to the log.

Why use async queries?

products_promise = Product.published.recent.limit(10).load_async
stats_promise = Order.where(created_at: 1.week.ago..).count_async
products = products_promise.value
stats = stats_promise.value

Queries execute in a background thread from the ActiveRecord pool. On PostgreSQL with multiple connections, this yields real gains for dashboard pages: in one project, we cut load time from 4 to 1.5 seconds.

Migrations with indexes

class CreateProducts < ActiveRecord::Migration[7.1]
  def change
    create_table :products do |t|
      t.string :title, limit: 500, null: false
      t.string :slug, limit: 520, null: false
      t.decimal :price, precision: 12, scale: 2, null: false
      t.string :status, limit: 20, null: false, default: 'draft'
      t.references :category, null: false, foreign_key: { on_delete: :restrict }
      t.boolean :is_featured, null: false, default: false
      t.jsonb :meta
      t.timestamps
    end
    add_index :products, :slug, unique: true
    add_index :products, [:status, :created_at]
    add_index :products, [:category_id, :status]
    add_index :products, :meta, using: :gin
  end
end

Composite indexes on frequently used field combinations speed up filtering by 10x. Choosing the right index type depends on the data:

Index type Use case Example field
B-tree (default) Equality and range created_at
GIN JSONB or full-text search meta
Unique Uniqueness slug

Transactions and integrity

ActiveRecord::Base.transaction do
  order = Order.create!(user: current_user, status: :pending)
  items.each do |item|
    order.order_items.create!(
      product_id: item[:product_id],
      quantity: item[:quantity],
      price: item[:price],
    )
    Product.find(item[:product_id]).decrement!(:stock, item[:quantity])
  end
end

create! and decrement! (with bang) raise exceptions on error — the transaction rolls back automatically.

What's included in turnkey ActiveRecord setup

  • Audit of current configuration and database schema
  • database.yml tuning with replica and timeouts
  • Model optimization: associations, scopes, validations
  • Migrations with proper indexes
  • Integration of Bullet for N+1 detection
  • Async queries for heavy pages
  • Operations documentation
  • Team training (1 hour)
  • One week of post-delivery support

How we work

  1. Analysis — we load current configuration, logs, slow queries.
  2. Design — we draft a change plan and get your approval.
  3. Implementation — we apply changes to configs, models, migrations.
  4. Testing — we verify on a staging copy, measure metrics.
  5. Deployment — we deploy and monitor for the first 24 hours.

Timelines and cost

ActiveRecord setup for a new project takes from 1 day. Optimization of an existing project takes 1–3 days. Cost is calculated individually based on scope. We have been working with Rails for over 5 years and have completed 30+ projects. Contact us for a preliminary assessment.

Get a consultation: write to us and we will conduct an audit of your database.