Controllers & Actions

Ruby on Rails Fundamentals — Controllers & Actions
Ruby on Rails Fundamentals
Course 1 · Chapter 3 · Controllers & Actions

🎮 Controllers & Actions

Chapter 2's resources :posts pointed seven routes at seven controller actions. This chapter writes those actions — and covers the single biggest behavioral surprise coming from Express: a Rails action doesn't have to explicitly send a response at all.

🏛️ ApplicationController

class PostsController < ApplicationController # actions go here end

Every Rails controller inherits from ApplicationController, itself a subclass of ActionController::Base — real Ruby classes using the inheritance and class syntax from both Ruby courses. Express has no equivalent concept at all: a "controller" there (as Chapter 1's example showed) is just a plain object of exported functions, with no shared base class or built-in framework hooks.

🎬 The Seven Actions

class PostsController < ApplicationController def index @posts = Post.all # Active Record -- fully covered in Chapter 5 end def show @post = Post.find(params[:id]) end def new @post = Post.new end def create @post = Post.new(post_params) if @post.save redirect_to @post else render :new end end def edit @post = Post.find(params[:id]) end def update @post = Post.find(params[:id]) if @post.update(post_params) redirect_to @post else render :edit end end def destroy Post.find(params[:id]).destroy redirect_to posts_path # the named route helper from Chapter 2 end end

Every method name matches an action from Chapter 2's route table exactly — that's not a coincidence, it's the same naming convention linking routes to controllers that Chapter 1 introduced.

👻 Implicit Rendering — the Biggest Surprise Coming From Express

⚠ index and show above never call render or res.json — and that's correct

In Express, forgetting to call res.send/res.json/res.render leaves the request hanging with no response at all — the framework never assumes what you meant to send back. Rails does the opposite: if an action doesn't explicitly call render or redirect_to, Rails automatically renders the view matching the action's name — index implicitly renders app/views/posts/index.html.erb, show implicitly renders app/views/posts/show.html.erb. This is convention over configuration applied to the controller/view boundary itself, and it's genuinely disorienting the first time a page renders correctly despite the action "doing nothing" to send a response.

📥 params — One Hash for Everything

# GET /posts/5?highlight=true def show params[:id] # => "5" -- from the route (:id in the URL pattern) params[:highlight] # => "true" -- from the query string end # POST /posts, with a form body of { post: { title: "Hi" } } def create params[:post][:title] # => "Hi" -- from the request body end

Rails merges route parameters, query string parameters, and request body parameters into a single params hash-like object — no need to know or care which source a given value came from. Express keeps these genuinely separate: req.params (route), req.query (query string), and req.body (parsed body, requiring middleware like express.json() to populate at all).

🔀 render vs redirect_to

render — same request, different content

Renders a view (or a different one than the action's default) for the current request — no new HTTP round trip, the URL in the browser doesn't change. Used above in create's failure branch, to redisplay the form with validation errors still in place.

redirect_to — a brand new request

Sends an HTTP redirect response, telling the browser to make an entirely new GET request to a different URL — the browser's address bar changes. Used above in create's success branch, sending the user to the new post's show page.

This maps directly onto Express's res.render(...) vs res.redirect(...) — same underlying HTTP distinction, just spelled with Rails' own method names.

📜 Handling a Request: Express vs Rails

Side by Side

ConceptExpressRails
Handler shapeA plain function: (req, res) => { ... }An instance method inside a class inheriting ApplicationController
Route paramsreq.paramsparams (merged with query + body)
Query stringreq.queryparams (same hash, no separate access)
Request bodyreq.body (needs body-parsing middleware)params (parsed automatically)
Must you send a response?Yes, always, explicitlyNo — implicit rendering falls back to a matching view

💻 Coding Challenges

Challenge 1: Write a Full Controller

Write a CommentsController with all seven actions, following the same pattern as this chapter's PostsController (you can use placeholder Active Record calls like Comment.find(params[:id]) even before Chapter 5 covers Active Record in depth). Comment above index and show explaining specifically which view file Rails will implicitly render for each.

Goal: Get the shape of all seven action methods, and the implicit-render convention, under your fingers.

→ Solution

Challenge 2: Reading From params

Given a request to GET /posts/12/comments?sort=newest, with route resources :posts { resources :comments } (Chapter 2), write the index action for CommentsController and show exactly how you'd read both the post's ID and the sort query parameter out of params.

Goal: Practice pulling values from Rails' unified params hash regardless of where they originated.

→ Solution

Challenge 3: render vs redirect_to

Write an update action for a ProductsController that, on a successful save, redirects to the product's show page, and on failure, re-renders the :edit view so the user sees their validation errors. Add a comment explaining what would go wrong (from the user's perspective) if redirect_to were used in the failure branch instead of render.

Goal: Internalize exactly when each of the two response methods is the correct choice.

→ Solution

💎 Implicit Rendering Is Convention Over Configuration's Purest Form

No routing table, no folder structure — just a controller action's name silently determining what gets rendered if you don't say otherwise. It's the single clearest example in this course so far of Chapter 1's warning made concrete: extremely little code, and genuinely confusing the first time a page renders correctly despite an action that appears to do nothing at all.

🎯 What's Next

Next chapter: Views & ERB — the templates those implicitly-rendered actions actually render, embedding Ruby directly in HTML, and how ERB compares to the EJS templating already covered in Express.