Controllers & Actions
Reviewed & published by Brayan K
In Ruby on Rails the controller is the coordinator: each public method, called an action, receives a request, works with models, and decides what to send back. It's the C in MVC.
Part of the free Ruby course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.
By the end of this lesson you'll write the standard CRUD actions, read the params hash, choose between render and redirect_to, and share setup with before_action.
What You'll Learn in This Lesson
- The seven CRUD actions
- Reading data from params
- render vs redirect_to
- Strong parameters
- Sharing setup with before_action
- Loading records with Model.find
1️⃣ Actions, params, render and redirect
Each action is a method on the controller. It reads input from params, talks to a model, and then either renders a view or redirect_tos another URL.
# app/controllers/posts_controller.rb
class PostsController < ApplicationController
# GET /posts -> list all posts
def index
@posts = Post.all
end
# GET /posts/:id -> show one post
def show
@post = Post.find(params[:id]) # params[:id] comes from the URL
end
# GET /posts/new -> render a blank form
def new
@post = Post.new
end
# POST /posts -> save the submitted form
def create
@post = Post.new(post_params)
if @post.save
redirect_to @post # success: go to the new post
else
render :new # failure: re-show the form
end
end
endThe remaining actions complete CRUD. Notice the private post_params method — strong parameters whitelist the fields you accept.
# The remaining CRUD actions: edit, update, destroy.
class PostsController < ApplicationController
# GET /posts/:id/edit -> form pre-filled with the record
def edit
@post = Post.find(params[:id])
end
# PATCH /posts/:id -> save changes
def update
@post = Post.find(params[:id])
if @post.update(post_params)
redirect_to @post
else
render :edit
end
end
# DELETE /posts/:id -> delete the record
def destroy
@post = Post.find(params[:id])
@post.destroy
redirect_to posts_path # back to the list
end
private
# Strong parameters: only allow these fields.
def post_params
params.require(:post).permit(:title, :body)
end
end2️⃣ Sharing Setup with before_action
Several actions need the same record. A before_action runs a method before chosen actions, so you load @post once instead of repeating the lookup.
# before_action runs shared setup before chosen actions.
class PostsController < ApplicationController
# Run set_post before show, edit, update, and destroy.
before_action :set_post, only: [:show, :edit, :update, :destroy]
def show; end # @post is already loaded
def edit; end # @post is already loaded
private
def set_post
@post = Post.find(params[:id]) # no more repeating this line!
end
endYour turn. Complete the index and show actions for articles.
# 🎯 YOUR TURN — complete the index and show actions.
class ArticlesController < ApplicationController
# 1) List every article.
def index
@articles = Article.____ # 👉 TODO: fetch them all
end
# 2) Show one article by its id from the URL.
def show
@article = Article.find(params[:____]) # 👉 TODO: the id key
end
end
# ✅ Expected:
# Article.all
# params[:id]Mini-Challenge: Match Action to Request
For each HTTP request, name the controller action that handles it.
# 🎯 MINI-CHALLENGE: name the right action.
# For each request, write the controller action that runs.
#
# 1. POST /posts -> ______
# 2. GET /posts/9/edit -> ______
# 3. PATCH /posts/9 -> ______
# 4. DELETE /posts/9 -> ______
#
# ✅ Example answers:
# create
# edit
# update
# destroy
# your answers hereCommon Errors (and the fix)
- ForbiddenAttributesError — You passed raw params to a model; use strong parameters with permit.
- render instead of redirect after save — On success, redirect_to so a refresh doesn't resubmit.
- "Double render error" — An action may render or redirect only once; add a return or restructure.
- RecordNotFound — Post.find raises if the id doesn't exist; check the id or use find_by.
- Wrong params key — Form fields nest under the model name, e.g. params[:post][:title].
Pro Tips
- 💡 Keep actions thin: push complex logic into models, not controllers.
- 💡 DRY with before_action: load shared records once.
- 💡 Redirect on success, render on failure: a reliable CRUD habit.
📋 Quick Reference — Controllers
| Concept | Syntax |
|---|---|
| List all | def index; @posts = Post.all; end |
| Find one | Post.find(params[:id]) |
| Show a view | render :new |
| Go elsewhere | redirect_to @post |
| Strong params | params.require(:post).permit(:title) |
| Shared setup | before_action :set_post |
🎉 Lesson Complete!
- ✅ Actions are methods like index, show, new, create, edit, update, destroy
- ✅ params holds request data
- ✅ render shows a view; redirect_to sends a new request
- ✅ Strong parameters whitelist safe fields
- ✅ before_action shares setup across actions
Practice quiz
Which controller action conventionally LISTS all records?
- show
- index
- create
- edit
Answer: index. The index action lists all records of a resource.
How does a controller read submitted form and URL data?
- Through the params hash
- Through the @request variable
- Through cookies only
- Through the routes file
Answer: Through the params hash. Incoming data (query string, form fields, path segments) is available in the params hash.
After a successful create, what should the controller usually do?
- render :new again
- redirect_to the new record (or its index)
- raise an error
- call params.save
Answer: redirect_to the new record (or its index). On success you typically redirect_to the record, following the POST-redirect-GET pattern.
What is the purpose of before_action?
- It deletes the database
- It runs shared setup code before chosen actions
- It defines the routes
- It renders the layout
Answer: It runs shared setup code before chosen actions. before_action runs a method before specified actions, ideal for shared setup like loading a record.
Which action handles the DELETE request to remove a record?
- remove
- delete
- destroy
- drop
Answer: destroy. The destroy action handles deletion of a record.
What does render :new do inside an action?
- Redirects the browser to /new
- Renders the new view template without a new request
- Creates a database record
- Defines a route
Answer: Renders the new view template without a new request. render :new displays the new template directly, keeping the current request (and any errors).
The difference between render and redirect_to is:
- They are identical
- render runs a migration; redirect_to deletes data
- render shows a view in the same request; redirect_to tells the browser to make a new request
- redirect_to is only for JSON
Answer: render shows a view in the same request; redirect_to tells the browser to make a new request. render produces a response now; redirect_to sends the browser to a new URL, triggering a fresh request.
In show, how do you find the record from the URL /posts/5?
- Post.all
- Post.new
- Post.find(params[:id])
- Post.delete(5)
Answer: Post.find(params[:id]). Post.find(params[:id]) looks up the record whose id matches the :id from the path.
Which pair of actions render forms rather than change data?
- new and edit
- create and update
- index and destroy
- show and create
Answer: new and edit. new and edit render forms; create and update are the actions those forms submit to.
Why use strong parameters like params.require(:post).permit(:title)?
- To speed up the server
- To allow only approved fields, preventing mass-assignment of unexpected data
- To define routes
- To render a partial
Answer: To allow only approved fields, preventing mass-assignment of unexpected data. Strong parameters whitelist permitted fields, protecting against unwanted mass assignment.
Continue this course
- Previous: Routing & RESTful Resources
- Next: Views, ERB & Partials — ERB tags, layouts, partials and view helpers
- Quick reference: Ruby cheat sheet
Frequently asked questions
What are the seven standard controller actions?
They mirror the seven RESTful routes: index lists all records, show displays one, new renders a blank form, create saves the submitted form, edit renders a form pre-filled with an existing record, update saves changes to it, and destroy deletes it. new and edit just render forms; create, update, and destroy actually change data. Following these names keeps your controller aligned with resources :posts in the routes file, so everything wires up automatically. Most CRUD controllers you write will have exactly these actions.
What is the params hash?
params is a hash-like object holding all the data that came in with the request: values from the URL path (like the :id in /posts/5, available as params[:id]), query string parameters, and submitted form fields (often nested, like params[:post][:title]). Your actions read params to know which record to load or what data to save. Because params can contain anything a user sends, you protect writes with strong parameters — params.require(:post).permit(:title, :body) — which only lets approved fields through.
What's the difference between render and redirect_to?
render produces a response within the current request: render :new shows the new template right now, which is why you use it when a save fails — the user keeps their input and sees the validation errors. redirect_to instead tells the browser to make a brand-new request to another URL, for example redirect_to @post after a successful create. The rule of thumb: render after a failure (so the form and errors persist) and redirect after a success (following the POST-redirect-GET pattern, which avoids duplicate submissions on refresh).
When should I use before_action?
Use before_action to run shared setup code before several actions, keeping your controller DRY. The classic case is loading a record: before_action :set_post, only: [:show, :edit, :update, :destroy] runs a set_post method that assigns @post = Post.find(params[:id]) once, instead of repeating that line in four actions. before_action is also used for things like requiring a logged-in user or authorizing access. You can scope it with only: or except: to control exactly which actions it runs before.