Ruby on Rails Controller Mastery

πŸš€ Ruby on Rails Controller Mastery

Write Clean, Scalable & Production-Ready Controllers Like a Pro πŸ’Ž

Controllers are the brain 🧠 of a Rails application. Poorly written controllers lead to fat controllers, bugs, and unmaintainable code. Well-designed controllers give you clarity, performance, and scalability.

Let’s master Rails Controllers with principles, tricks, hacks, best practices, and mistakes to avoid β€” all with real examples πŸ‘‡

ChatGPT Image Jan 3, 2026, 11_50_31 PM


🎯 What Is a Rails Controller (Quick Recap)

A controller:

  • Receives HTTP requests 🌐
  • Talks to models πŸ“¦
  • Decides what response to send (HTML/JSON/etc.) πŸ“€

πŸ‘‰ Golden Rule:

Controllers should orchestrate β€” not compute.


🧠 Core Principles of Controller Mastery

1️⃣ Skinny Controller, Fat Model (or Service) πŸ‹οΈβ€β™‚οΈ

Controllers should be thin. Business logic belongs elsewhere.

❌ Bad

def create
  user = User.new(user_params)
  user.token = SecureRandom.hex
  user.save!
end

βœ… Good

def create
  UserSignupService.new(user_params).call
end

πŸ“Œ Move logic to:

  • Models
  • Service Objects
  • Query Objects

2️⃣ One Action = One Responsibility 🎯

Each action should do ONE thing only.

❌ Bad

def create
  @user = User.create(user_params)
  send_email
  track_analytics
end

βœ… Good

def create
  @user = User.create!(user_params)
  UserMailer.welcome(@user).deliver_later
end

3️⃣ RESTful Controllers Are Non-Negotiable 🌍

Stick to Rails conventions:

Action Purpose
index List
show View
new Form
create Save
edit Edit form
update Update
destroy Delete

πŸ“Œ Convention > Configuration


🧩 Controller Best Practices (With Hacks)

4️⃣ Use before_action Wisely ⚠️

DRY your code, but don’t overuse.

before_action :set_user, only: [:show, :edit, :update]

def set_user
  @user = User.find(params[:id])
end

🚨 Avoid:

  • Too many callbacks
  • Hidden side effects

5️⃣ Strong Parameters Are Mandatory πŸ”

Never trust user input.

def user_params
  params.require(:user).permit(:name, :email)
end

πŸ”₯ Pro Hack: Use fetch for APIs

params.fetch(:user, {}).permit(:name)

6️⃣ Use respond_to for Multiple Formats πŸ”„

Perfect for APIs + Web apps.

respond_to do |format|
  format.html
  format.json { render json: @users }
end

7️⃣ Render vs Redirect β€” Know the Difference 🚦

Method What it does
render Same request
redirect_to New request

❌ Buggy

redirect_to users_path
render :index # ❌ Double render error

8️⃣ Use Namespaced Controllers for APIs 🧩

Clean separation.

module Api
  module V1
    class UsersController < ApplicationController
      def index
        render json: User.all
      end
    end
  end
end

πŸš€ Advanced Controller Hacks

9️⃣ Use concerns for Shared Logic ♻️

module Authenticable
  extend ActiveSupport::Concern

  included do
    before_action :authenticate_user!
  end
end
class DashboardController < ApplicationController
  include Authenticable
end

πŸ”Ÿ Pagination at Controller Level πŸ“„

@users = User.page(params[:page]).per(10)

Never load thousands of records πŸ˜΅β€πŸ’«


1️⃣1️⃣ Authorization in Controllers πŸ›‘οΈ

With Pundit:

authorize @post

With CanCanCan:

authorize! :update, @post

1️⃣2️⃣ Handle Errors Gracefully 🚨

rescue_from ActiveRecord::RecordNotFound do
  render file: "public/404.html", status: :not_found
end

πŸ”₯ Pro tip: Centralize error handling in ApplicationController.


⚠️ Common Controller Mistakes to Avoid

❌ 1. Fat Controllers

πŸ‘‰ Business logic inside controller = ❌


❌ 2. Direct SQL in Controllers

User.where("age > 18") # ❌

Move queries to:

  • Scopes
  • Query objects

❌ 3. Overusing Callbacks

Too many before_action makes code hard to debug.


❌ 4. Ignoring Security

  • Missing strong params
  • No authentication
  • No authorization

❌ 5. Returning Models Directly in APIs

render json: @user # ❌

Use:

  • Serializers
  • JBuilder
  • Blueprinter

πŸ—οΈ Ideal Controller Structure (Pro Template)

class UsersController < ApplicationController
  before_action :set_user, only: %i[show update destroy]

  def index
    @users = User.all
  end

  def show; end

  def create
    @user = User.create!(user_params)
  end

  private

  def set_user
    @user = User.find(params[:id])
  end

  def user_params
    params.require(:user).permit(:name, :email)
  end
end

Clean ✨ Readable πŸ‘€ Maintainable 🧠


🧠 Final Controller Mastery Rules (Remember This πŸ’‘)

βœ… Controllers orchestrate, not calculate βœ… Keep actions small βœ… Follow REST & Rails conventions βœ… Extract logic early βœ… Secure everything

πŸ’¬ β€œA great Rails app is judged by how boring its controllers are.”

© Lakhveer Singh Rajput - Blogs. All Rights Reserved.