ActiveRecord Patterns

This skill should be used when the user asks about "ActiveRecord", "database queries", "query optimization", "N+1 queries", "eager loading", "associations", "migrations", "database indexes", "SQL performance", "ActiveRecord callbacks", "scopes", or needs guidance on efficient database access patterns in Rails 7+.

16 stars

Best use case

ActiveRecord Patterns is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

This skill should be used when the user asks about "ActiveRecord", "database queries", "query optimization", "N+1 queries", "eager loading", "associations", "migrations", "database indexes", "SQL performance", "ActiveRecord callbacks", "scopes", or needs guidance on efficient database access patterns in Rails 7+.

Teams using ActiveRecord Patterns should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/activerecord-patterns/SKILL.md --create-dirs "https://raw.githubusercontent.com/diegosouzapw/awesome-omni-skill/main/skills/backend/activerecord-patterns/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/activerecord-patterns/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How ActiveRecord Patterns Compares

Feature / AgentActiveRecord PatternsStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

This skill should be used when the user asks about "ActiveRecord", "database queries", "query optimization", "N+1 queries", "eager loading", "associations", "migrations", "database indexes", "SQL performance", "ActiveRecord callbacks", "scopes", or needs guidance on efficient database access patterns in Rails 7+.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# ActiveRecord Patterns for Production Rails

Production-focused guidance for ActiveRecord query optimization, associations, migrations, and database best practices for Rails 7+.

## Query Optimization

### Avoiding N+1 Queries

Always use `includes`, `preload`, or `eager_load` when accessing associations:

```ruby
# Bad - N+1 query
Order.all.each { |o| puts o.user.email }

# Good - eager loading
Order.includes(:user).each { |o| puts o.user.email }

# For nested associations
Order.includes(line_items: :product).each do |order|
  order.line_items.each { |li| puts li.product.name }
end
```

**When to use each:**
- `includes` - Rails decides (usually `preload`)
- `preload` - Separate queries, works with `limit`
- `eager_load` - LEFT OUTER JOIN, needed for filtering

```ruby
# Filtering on association - must use eager_load
Order.eager_load(:line_items)
     .where(line_items: { product_id: 123 })
```

### Select Only Needed Columns

```ruby
# Bad - loads all columns
User.all.map(&:email)

# Good - loads only needed columns
User.pluck(:email)

# When you need objects with limited columns
User.select(:id, :email, :name)
```

### Batch Processing

```ruby
# Bad - loads all records into memory
User.all.each { |u| u.update(last_contacted_at: Time.current) }

# Good - processes in batches
User.find_each(batch_size: 1000) do |user|
  user.update(last_contacted_at: Time.current)
end

# For parallelization
User.in_batches(of: 1000) do |batch|
  batch.update_all(last_contacted_at: Time.current)
end
```

### Counting and Existence

```ruby
# Bad - loads records to count
User.all.count        # Loads all, then counts
User.all.length       # Same problem

# Good - database count
User.count            # SELECT COUNT(*)

# For checking existence
User.any?             # Avoid - can be slow
User.exists?          # SELECT 1 LIMIT 1 - fast
User.where(admin: true).exists?
```

## Associations

### Association Options

```ruby
class Order < ApplicationRecord
  belongs_to :user, counter_cache: true
  belongs_to :created_by, class_name: "User", optional: true

  has_many :line_items, dependent: :destroy
  has_many :products, through: :line_items

  has_one :invoice, dependent: :destroy

  # Polymorphic
  has_many :comments, as: :commentable

  # Self-referential
  belongs_to :parent_order, class_name: "Order", optional: true
  has_many :child_orders, class_name: "Order", foreign_key: :parent_order_id
end
```

### Counter Cache

```ruby
# Migration
add_column :users, :orders_count, :integer, default: 0, null: false

# Reset existing counts
User.find_each do |user|
  User.reset_counters(user.id, :orders)
end

# Model
class Order < ApplicationRecord
  belongs_to :user, counter_cache: true
end

# Usage - no query needed
user.orders_count
```

### Inverse Of

Define explicitly for complex associations:

```ruby
class Order < ApplicationRecord
  has_many :line_items, inverse_of: :order
end

class LineItem < ApplicationRecord
  belongs_to :order, inverse_of: :line_items
end

# Prevents extra queries when building
order = Order.new
order.line_items.build(quantity: 1)
order.line_items.first.order  # Same object, no query
```

## Scopes and Queries

### Named Scopes

```ruby
class Order < ApplicationRecord
  scope :recent, -> { where("created_at > ?", 30.days.ago) }
  scope :pending, -> { where(status: :pending) }
  scope :completed, -> { where(status: :completed) }
  scope :for_user, ->(user) { where(user: user) }

  # Composable scopes
  scope :recent_pending, -> { recent.pending }

  # Scope with default
  scope :by_status, ->(status = :pending) { where(status: status) }
end

# Chaining
Order.recent.pending.for_user(current_user)
```

### Class Methods vs Scopes

Use class methods for complex logic:

```ruby
class Order < ApplicationRecord
  def self.search(query)
    return all if query.blank?

    where("order_number ILIKE ? OR notes ILIKE ?",
          "%#{query}%", "%#{query}%")
  end

  def self.total_revenue
    completed.sum(:total)
  end
end
```

### Arel for Complex Queries

```ruby
class Order < ApplicationRecord
  def self.with_high_value_items
    line_items_table = LineItem.arel_table
    orders_table = arel_table

    joins(:line_items)
      .where(line_items_table[:price].gt(100))
      .distinct
  end
end
```

## Migrations

### Production-Safe Migrations

```ruby
class AddIndexToOrdersUserIdConcurrently < ActiveRecord::Migration[7.1]
  disable_ddl_transaction!

  def change
    add_index :orders, :user_id, algorithm: :concurrently,
              if_not_exists: true
  end
end
```

### Column Additions with Defaults

```ruby
# Rails 7+ handles this safely
class AddStatusToOrders < ActiveRecord::Migration[7.1]
  def change
    add_column :orders, :status, :string, default: "pending", null: false
  end
end
```

### Safe Column Removal

```ruby
# Step 1: Stop using column in code (deploy first)
# Step 2: Ignore column
class Order < ApplicationRecord
  self.ignored_columns += ["legacy_status"]
end

# Step 3: Remove column (separate deploy)
class RemoveLegacyStatusFromOrders < ActiveRecord::Migration[7.1]
  def change
    safety_assured { remove_column :orders, :legacy_status }
  end
end
```

### Indexing Strategy

```ruby
# Foreign keys - always index
add_index :orders, :user_id

# Composite index for common queries
add_index :orders, [:user_id, :status]

# Partial index for specific conditions
add_index :orders, :created_at,
          where: "status = 'pending'",
          name: "index_orders_pending_created_at"

# Unique constraint
add_index :users, :email, unique: true

# GIN index for array/JSON columns
add_index :products, :tags, using: :gin
```

## Transactions

### Basic Transactions

```ruby
Order.transaction do
  order = Order.create!(order_params)
  order.line_items.create!(line_item_params)
  InventoryService.deduct(order)
end
```

### Nested Transactions

```ruby
Order.transaction do
  order.update!(status: :processing)

  Order.transaction(requires_new: true) do
    # This savepoint can fail independently
    PaymentService.charge(order)
  rescue PaymentError => e
    order.update!(payment_error: e.message)
  end
end
```

### Advisory Locks

```ruby
# Prevent concurrent processing
Order.with_advisory_lock("order_#{order.id}") do
  process_order(order)
end
```

## Callbacks

### Safe Callback Patterns

```ruby
class Order < ApplicationRecord
  # Good: Simple, side-effect free callbacks
  before_validation :normalize_email
  before_save :set_defaults

  private

  def normalize_email
    self.email = email&.downcase&.strip
  end

  def set_defaults
    self.order_number ||= generate_order_number
  end
end
```

### When to Avoid Callbacks

Move business logic to service objects:

```ruby
# Avoid: Complex callback chains
class Order < ApplicationRecord
  after_create :send_confirmation, :update_inventory, :notify_warehouse
end

# Prefer: Explicit service object
class Orders::CreateService
  def call(params)
    Order.transaction do
      order = Order.create!(params)
      OrderMailer.confirmation(order).deliver_later
      Inventory::DeductService.new(order).call
      Warehouse::NotifyJob.perform_later(order.id)
      order
    end
  end
end
```

## Connection Management

### Connection Pool Configuration

```yaml
# config/database.yml
production:
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  checkout_timeout: 5
  reaping_frequency: 10
```

### Read Replicas (Rails 6+)

```ruby
# config/database.yml
production:
  primary:
    database: myapp_production
  primary_replica:
    database: myapp_production
    replica: true

# Usage
ActiveRecord::Base.connected_to(role: :reading) do
  Order.where(status: :pending).count
end

# Automatic switching
class ApplicationController < ActionController::Base
  around_action :switch_to_replica, only: [:index, :show]

  private

  def switch_to_replica
    ActiveRecord::Base.connected_to(role: :reading) { yield }
  end
end
```

## Additional Resources

### Reference Files

For detailed patterns and advanced techniques:
- **`references/query-patterns.md`** - Complex query patterns, CTEs, window functions
- **`references/migration-safety.md`** - Zero-downtime migration strategies

Related Skills

multi-agent-patterns

16
from diegosouzapw/awesome-omni-skill

Supervisor, swarm, and hierarchical multi-agent architectures with context isolation patterns.

memory-safety-patterns

16
from diegosouzapw/awesome-omni-skill

Implement memory-safe programming with RAII, ownership, smart pointers, and resource management across Rust, C++, and C. Use when writing safe systems code, managing resources, or preventing memory...

llm-app-patterns

16
from diegosouzapw/awesome-omni-skill

Production-ready patterns for building LLM applications. Covers RAG pipelines, agent architectures, prompt IDEs, and LLMOps monitoring. Use when designing AI applications, implementing RAG, building agents, or setting up LLM observability.

dbt-transformation-patterns

16
from diegosouzapw/awesome-omni-skill

Master dbt (data build tool) for analytics engineering with model organization, testing, documentation, and incremental strategies. Use when building data transformations, creating data models, or ...

data-fetching-patterns

16
from diegosouzapw/awesome-omni-skill

Explains data fetching strategies including fetch on render, fetch then render, render as you fetch, and server-side data fetching. Use when implementing data loading, optimizing loading performance, or choosing between client and server data fetching.

airflow-dag-patterns

16
from diegosouzapw/awesome-omni-skill

Build production Apache Airflow DAGs with best practices for operators, sensors, testing, and deployment. Use when creating data pipelines, orchestrating workflows, or scheduling batch jobs.

ai-product-patterns

16
from diegosouzapw/awesome-omni-skill

Builds AI-native products using OpenAI's development philosophy and modern AI UX patterns. Use when integrating AI features, designing for model improvements, implementing evals as product specs, or creating AI-first experiences. Based on Kevin Weil (OpenAI CPO) on building for future models, hybrid approaches, and cost optimization.

a2a-executor-patterns

16
from diegosouzapw/awesome-omni-skill

Agent-to-Agent (A2A) executor implementation patterns for task handling, execution management, and agent coordination. Use when building A2A executors, implementing task handlers, creating agent execution flows, or when user mentions A2A protocol, task execution, agent executors, task handlers, or agent coordination.

GitOps Patterns

16
from diegosouzapw/awesome-omni-skill

ArgoCD ApplicationSets, progressive delivery, Harness GitX, and multi-cluster GitOps patterns

dotnet-gha-patterns

16
from diegosouzapw/awesome-omni-skill

Composes GitHub Actions workflows. Reusable workflows, composite actions, matrix, caching.

bats-testing-patterns

16
from diegosouzapw/awesome-omni-skill

Comprehensive guide for writing shell script tests using Bats (Bash Automated Testing System). Use when writing or improving tests for Bash/shell scripts, creating test fixtures, mocking commands, or setting up CI/CD for shell script testing. Includes patterns for assertions, setup/teardown, mocking, fixtures, and integration with GitHub Actions.

bash-defensive-patterns

16
from diegosouzapw/awesome-omni-skill

Master defensive Bash programming techniques for production-grade scripts. Use when writing robust shell scripts, CI/CD pipelines, or system utilities requiring fault tolerance and safety.