Ruby on Rails Clean Code & Best Practices
π Ruby on Rails Clean Code & Best Practices: Write Like a Pro! π
In the fast-paced world of web development, clean code is not just a buzzwordβitβs the backbone of scalable, maintainable, and bug-free applications. β¨ Ruby on Rails (RoR) already promotes convention over configuration, but writing clean and optimized code requires deliberate effort.
Letβs explore Rails clean code principles, best practices, and optimization tips with practical examples to make your applications elegant and performant! π₯
π§Ό 1. Follow the Single Responsibility Principle (SRP)
Each class, method, or module should have one and only one job. This keeps code easy to test, modify, and scale.
β Bad Example:
class User < ApplicationRecord
def send_welcome_email
UserMailer.welcome(self).deliver_now
end
def calculate_age
Date.today.year - birthdate.year
end
end
π The model handles database logic, email sending, and calculations. Too many responsibilities!
β Clean Example:
class User < ApplicationRecord
def calculate_age
Date.today.year - birthdate.year
end
end
class UserMailerService
def self.send_welcome_email(user)
UserMailer.welcome(user).deliver_now
end
end
π Tip: Keep models focused on data-related tasks. Offload emails, calculations, and heavy logic to service objects.
π― 2. Fat Model, Skinny Controller πͺ
Rails encourages MVC. Keep controllers thin by avoiding complex logic.
β Bad Example:
class OrdersController < ApplicationController
def create
@order = Order.new(order_params)
if @order.valid? && stock_available?(@order)
@order.save
OrderMailer.confirmation(@order).deliver_now
else
render :new
end
end
end
β Clean Example:
class OrdersController < ApplicationController
def create
@order = OrderService.new(order_params).create
redirect_to @order
rescue OrderService::Error => e
flash[:alert] = e.message
render :new
end
end
# app/services/order_service.rb
class OrderService
def initialize(params)
@params = params
end
def create
order = Order.new(@params)
raise Error, "Stock unavailable" unless stock_available?(order)
order.save!
OrderMailer.confirmation(order).deliver_later
order
end
end
π Tip: Use Service Objects for business logic. Controllers should simply handle HTTP requests/responses.
π§© 3. Use Partials & View Helpers
Avoid repeating HTML/Ruby logic in views.
β Bad Example:
<!-- show.html.erb -->
<p><%= @user.name %></p>
<p><%= @user.email %></p>
<p><%= @user.address %></p>
β Clean Example:
<!-- show.html.erb -->
<%= render 'user_details', user: @user %>
<!-- _user_details.html.erb -->
<p><%= user.name %></p>
<p><%= user.email %></p>
<p><%= user.address %></p>
π Tip: Use helpers for formatting, e.g., number_to_currency(price)
instead of inline Ruby.
ποΈ 4. Keep a Clear Folder Structure
Rails gives a default structureβrespect it!
- β app/services/ for service objects
- β app/presenters/ for view logic
- β lib/ for custom modules
π‘ Pro Tip: Avoid dumping everything in models
or controllers
. Organize for clarity.
π§΅ 5. Use Scopes for Query Logic
Move queries from controllers/models into scopes for reusability.
β Bad Example:
@users = User.where(active: true).order(created_at: :desc)
β Clean Example:
class User < ApplicationRecord
scope :active, -> { where(active: true) }
scope :recent, -> { order(created_at: :desc) }
end
@users = User.active.recent
π Tip: Chainable scopes improve readability and testing.
π§ͺ 6. Write Tests (Rspec/Minitest)
Clean code is incomplete without tests.
- β Unit Tests for models and services
- β Integration Tests for controllers
- β System Tests for user flows
Example RSpec Test:
RSpec.describe User, type: :model do
it "validates email presence" do
user = User.new(email: nil)
expect(user.valid?).to be_falsey
end
end
π‘οΈ Tests prevent regressions and enforce code quality.
β‘ 7. Optimize Database Queries
Poor queries can kill performance.
- β Use includes to avoid N+1 queries.
- β Add indexes for faster lookups.
β Bad Example:
# N+1 problem
User.all.each do |user|
puts user.posts.count
end
β Clean Example:
User.includes(:posts).each do |user|
puts user.posts.size
end
π Tip: Use gems like bullet
to detect N+1 issues during development.
π 8. Caching for Speed
Rails provides multiple caching options:
- Page caching: Cache entire pages.
- Action caching: Cache controller actions.
- Fragment caching: Cache partials.
Example:
<% cache(@product) do %>
<%= render @product %>
<% end %>
π‘ Combine caching with Redis for a significant performance boost.
ποΈ 9. Background Jobs for Heavy Tasks
Avoid blocking requests with long-running tasks. Use Active Job with Sidekiq/Resque.
Example:
class ReportJob < ApplicationJob
queue_as :default
def perform(user)
ReportMailer.weekly(user).deliver_now
end
end
π Then call:
ReportJob.perform_later(current_user)
β‘ This keeps the user experience smooth.
π§βπ» 10. Keep Gems Minimal & Updated
Too many gems = slower boot time & security risks.
- β
Audit with
bundle audit
- β Prefer standard Ruby/Rails features over unnecessary gems.
π‘ Additional Tips for an Optimized Rails App
β
Use ENV variables (dotenv
) for credentials.
β
Enable Rails eager loading in production.
β
Use PG or MySQL indexes wisely.
β
Profile code with tools like rack-mini-profiler
.
β
Leverage Webpacker/Importmaps for faster asset loading.
β¨ Final Words
Clean code isnβt just about beautyβitβs about maintainability, performance, and developer happiness. π By following these best practices, youβll not only make your Ruby on Rails apps faster π but also easier to scale and collaborate on.
Remember: Clean Code = Happy Future You π
π Letβs Discuss!
π¬ Whatβs your favorite Rails clean code hack? Drop a comment below and share your wisdom with the Rails community! π
© Lakhveer Singh Rajput - Blogs. All Rights Reserved.