ActiveRecord Production Setup for Ruby on Rails

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. Ou

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

  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1287
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1246
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    983
  • image_crm_chasseurs_493_0.webp
    CRM development for Chasseurs
    1034
  • image_website-sbh_0.webp
    Website development for SBH Partners
    1108
  • image_website-_0.webp
    Website development for Red Pear
    555

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 a free audit of your database.