Do’s and Don’ts in Active Record
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
end3. 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
endInstead 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
end4. 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)
endInstead of:
# ❌ Loading all records at once (may cause memory issues)
User.all.each do |user|
user.update(active: false)
end5. 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
endInstead, 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
endInstead, use eager loading:
# ✅ Preload related data
users = User.includes(:orders)
users.each do |user|
puts user.orders.count
end5. 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! 🚀





