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! πŸ”₯

0_nuTDY9z8lYUcrpKZ


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