-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Methods and Blocks
-
Section 4: Object-Oriented Ruby
-
Section 5: Metaprogramming
-
Section 6: Working with Data and Files
-
Section 7: Ruby Frameworks Overview
-
Section 8: Ecosystem and Testing
-
Section 9: Practical Projects
-
Section 10: Interview Practice
-
Section 11: Data Structures and Algorithms in Ruby
-
Section 12: More Practice Exercises
-
Section 13: Enumerable and Functional Style
-
Section 14: More OOP Practice
-
Section 15: More Testing
-
Section 16: Enumerable and Comparable Modules In Depth
-
Section 17: Ruby Standard Library: Core Utilities
-
Section 18: Ruby Standard Library: Data and Security
-
Section 19: Ruby Standard Library: CLI and Text
-
Section 20: Ruby Networking
-
Section 21: Ruby on Rails Deep Dive
-
Section 22: Ruby Metaprogramming Deep Dive
-
Section 23: Ruby Design Patterns
-
Section 24: Ruby Concurrency
-
Section 25: Ruby Testing Deep Dive
-
Section 26: Ruby Gems and Packaging
-
Section 27: Ruby Performance
-
Section 28: More Practice Exercises
-
Section 29: More Interview Practice
-
Section 30: Rails API Development
-
Section 31: Rails Authentication and Authorization
-
Section 32: Rails Testing Deep Dive
-
Section 33: Rails Performance
-
Section 34: Rails Deployment
-
Section 35: Sinatra and Lightweight Ruby Web Apps
-
Section 36: More Ruby Language Deep Dive
-
Section 37: Ruby 3.x Modern Features
-
Section 38: More Data Structures in Ruby
-
Section 39: More Practical Projects
-
Section 40: Ruby Ecosystem Tools
-
Section 41: More Practice and Review
-
Section 42: Final Practice and Mastery
-
Section 43: Ruby Interview Deep Dive
-
Section 44: Ruby Background Processing Deep Dive
-
Section 45: Ruby GraphQL
-
Section 46: Ruby Object Model Deep Dive
-
Section 47: Ruby Hanami Framework Overview
-
Section 48: Ruby gRPC and Protocol Buffers
-
Section 49: Ruby Data Processing
-
Section 50: Ruby Search Integration
-
Section 51: Ruby File Upload and Media
-
Section 52: Ruby Email and Notifications
-
Section 53: Ruby Admin Panels
-
Section 54: Ruby Feature Flags and Experimentation
-
Section 55: Ruby Monitoring and Observability
-
Section 56: Ruby Docker and Deployment Deep Dive
-
Section 57: Ruby Security Deep Dive
-
Section 58: More Advanced Metaprogramming
-
Section 59: More Final Projects
180: Common Ruby Interview Questions on Rails Request Lifecycle
One of the most common things I see in technical interviews for mid-to-senior Rails roles is a question like, "Walk me through the lifecycle of a request." Most candidates can give a textbook answer: "It hits the router, goes to the controller, hits the model, and renders a view." But that's the surface level. The real meat—and where people usually trip up—is what happens before the router even knows the request exists.
Let's look at a bug I encountered a few years ago. I was building a custom audit logger as a piece of Rack middleware to track which users were accessing specific internal API endpoints. I wanted to log the user_id from the session for every single request.
# app/middleware/request_audit_logger.rb
class RequestAuditLogger
def initialize(app)
@app = app
end
def call(env)
# I wanted to grab the user_id from the session here
user_id = env['rack.session'][:user_id]
Rails.logger.info "Request received for User: #{user_id}"
@app.call(env)
end
end
# config/application.rb
config.middleware.use RequestAuditLogger
The "Nil" Session Mystery
When I deployed this, the logs didn't show user IDs. In fact, they just showed User: . Even worse, if I tried to call a method on user_id, the whole app crashed with a NoMethodError. I checked my session logic, and it was working perfectly in the controllers. I couldn't understand why the session was empty in the middleware but full in the controller.
The problem is that I forgot that the "Request Lifecycle" is actually a stack. When you use config.middleware.use, Rails appends your middleware to the end of the stack, but the order still matters relative to other built-in middleware. In this case, I was trying to access env['rack.session'] before the ActionDispatch::Session::CookieStore middleware had even run. The session hasn't been "hydrated" from the cookies yet, so env['rack.session'] is simply nil.
Ordering Middleware for Session Access
To fix this, I had to tell Rails exactly where to put my logger in the sequence. I needed it to run after the session middleware but before the request hit the router.
# config/application.rb
# Instead of .use, we explicitly place it after the session store
config.middleware.insert_after ActionDispatch::Session::CookieStore, RequestAuditLogger
By moving the middleware down the chain, the request first passes through the CookieStore (which populates the session hash), and then it hits my logger. Now, env['rack.session'] is populated, and the bug disappears. This is the "onion" model of Rails: every request peels through layers of middleware before it ever reaches your routes.rb file.
The Path from Rack to ActionController
When an interviewer asks about the lifecycle, I recommend you describe it as a series of hand-offs. If you can explain it in this order, you'll sound like someone who actually understands the internals, not someone who just memorized a cheat sheet:
- The Web Server: Puma or Unicorn receives the raw HTTP request and wraps it in a Rack environment hash (
env). - The Rack Middleware Stack: The request passes through a series of "filters" (like
Rack::Sendfile,ActionDispatch::Cookies, andActionDispatch::Session). This is where the "heavy lifting" of the environment setup happens. - The Router:
ActionDispatch::Routinglooks at the URL and HTTP method to determine which controller and action should handle the request. - The Controller Callbacks: Before the action runs, Rails executes
before_actionfilters. This is the primary place for authentication and authorization. - The Action: The actual method in your controller executes, interacting with Models (ActiveRecord) to fetch or save data.
- The View Rendering: The controller passes instance variables to the view (ActionView), which compiles the HTML or JSON.
- The Response: The resulting string travels back up the middleware stack (where middleware can modify the headers or body) and is sent back to the client.
Controller Callbacks vs. Middleware
You might wonder: "Why put logic in middleware if I can just use a before_action?" I've seen this come up in interviews a lot. The key difference is scope. A before_action only runs if the Router successfully matches a request to a controller. If a request hits a 404 or a middleware crashes, your before_action never executes.
Middleware is for "global" concerns—things like request timing, security headers, or session management—that must happen regardless of which controller is being called. Controller callbacks are for "business" concerns—like checking if a user is an admin for a specific set of pages.
📋 Practical Task
Exercise: Resolving the Middleware Collision
You are tasked with implementing a RequestTimerMiddleware that calculates how long a request takes to process. However, you've noticed that your application has a custom MaintenanceModeMiddleware that returns a 503 status code if a global flag is set. Currently, your timer is running before the maintenance check, meaning you are timing requests that are blocked by maintenance, which is skewing your performance metrics.
Your Goal: Modify the middleware configuration to ensure the RequestTimerMiddleware only starts timing after the MaintenanceModeMiddleware has allowed the request to pass through.
# Current configuration in config/application.rb
config.middleware.use MaintenanceModeMiddleware
config.middleware.use RequestTimerMiddleware
Requirements:
- Update the
config/application.rblogic to ensure theRequestTimerMiddlewareis positioned afterMaintenanceModeMiddleware. - While
.useappends to the end, assume for this exercise that other middlewares are being dynamically inserted. Useinsert_afterto be explicit about the dependency. - Write a brief comment explaining why
insert_afteris safer than.usein a complex application with many gems adding their own middleware.
There are no comments for now.