Sitemap

Do’s and Don’ts in Active Record

2 min readFeb 26, 2025

--

Active Record is a powerful ORM (Object-Relational Mapping) in Ruby on Rails that simplifies database interactions. However, misusing it can lead to performance issues and maintainability problems. This guide covers essential do’s and don’ts to help you write clean, efficient, and scalable Active Record code.

✅ Do’s in Active Record

1. Use Query Optimization Techniques

Active Record provides powerful querying capabilities, but writing inefficient queries can lead to performance bottlenecks.

Example:

# ✅ Use SELECT to fetch only required columns
User.select(:id, :name).where(active: true)

Instead of:

# ❌ Fetching all columns unnecessarily
User.where(active: true)

2. Use Indexes for Faster Queries

Indexes speed up queries significantly. Always add indexes to frequently searched columns.

class AddIndexToUsersEmail < ActiveRecord::Migration[6.0]
def change
add_index :users, :email, unique: true
end
end

3. Use Eager Loading to Prevent N+1 Queries

N+1 queries occur when querying associated records inefficiently.

# ✅ Eager load associated records
users = User.includes(:posts).where(active: true)
users.each do |user|
puts user.posts.count
end

Instead of:

# ❌ Causing N+1 query problem
users = User.where(active: true)
users.each do |user|
puts user.posts.count # Triggers an extra query per user
end

4. Use find_each for Large Datasets

When processing large datasets, find_each loads records in batches, avoiding memory overload.

# ✅ Process records in batches
User.find_each(batch_size: 1000) do |user|
user.update(active: false)
end

Instead of:

# ❌ Loading all records at once (may cause memory issues)
User.all.each do |user|
user.update(active: false)
end

5. Use Transactions for Bulk Updates

Transactions ensure that all database operations succeed or fail together, preventing partial updates.

# ✅ Wrap multiple operations in a transaction
ActiveRecord::Base.transaction do
order.update(status: 'completed')
order.user.update(balance: order.user.balance - order.total)
end

❌ Don’ts in Active Record

1. Avoid Using .all for Large Queries

Fetching all records without filtering can overload the database.

# ❌ Avoid loading all users
User.all.each { |user| puts user.name }

Use scopes and conditions instead:

# ✅ Fetch only required records
User.where(active: true).find_each { |user| puts user.name }

2. Don’t Use Callbacks Excessively

While callbacks (before_save, after_create, etc.) are useful, overusing them can make debugging difficult.

# ❌ Too many callbacks clutter the model
class User < ApplicationRecord
before_save :normalize_name
after_create :send_welcome_email
after_destroy :log_deletion
end

Instead, move business logic to service objects.

3. Don’t Use update_all Without Validations

update_all skips model validations and callbacks, which can lead to inconsistencies.

# ❌ Updates without validation
User.update_all(active: false)

Use update instead:

# ✅ Ensures validation and callbacks run
User.find_each { |user| user.update(active: false) }

4. Avoid Performing Queries Inside Loops

Fetching records inside loops leads to inefficient queries.

# ❌ Query inside loop
User.all.each do |user|
puts user.orders.count
end

Instead, use eager loading:

# ✅ Preload related data
users = User.includes(:orders)
users.each do |user|
puts user.orders.count
end

5. Avoid Using pluck and map Together

Using .pluck and .map together is redundant.

# ❌ Unnecessary use of `map`
User.pluck(:email).map(&:downcase)

Use only .pluck:

# ✅ Directly fetch transformed data
User.pluck(Arel.sql('LOWER(email)'))

Conclusion

Active Record is a fantastic tool, but improper usage can cause performance issues. Following these do’s and don’ts will help you write efficient, maintainable, and scalable database queries in Rails.

Get Veeresh YH’s stories in your inbox

Join Medium for free to get updates from this writer.

Do you have other Active Record best practices? Share them in the comments! 🚀

--

--