Rails controllers and views

rails new

Rails is a gem and a generator. rails new writes a whole project: a Gemfile, an application class, a config folder and a bin/ with the commands. The generator pulls a large dependency tree, so these commands ran on the host in the ruby:3.4 image:

gem install rails

31 gems installed

rails new demo

... create db/cable_schema.rb force config/cable.yml

cd demo

The new project has a database configured, a test setup and a development server. bin/rails about prints the versions, which is the first command to run when a tutorial and the installed Rails disagree.

A resource route

A scaffold generates the model, the controller, the views and the route for one resource. The route is one line in config/routes.rb:

Rails.application.routes.draw do resources :todos end

bin/rails generate scaffold Todo title:string done:boolean

invoke active_record create db/migrate/20261105004223_create_todos.rb create app/models/todo.rb invoke test_unit create test/models/todo_test.rb create test/fixtures/todos.yml invoke resource_route route resources :todos invoke scaffold_controller create app/controllers/todos_controller.rb invoke erb create app/views/todos create app/views/todos/index.html.erb create app/views/todos/edit.html.erb create app/views/todos/show.html.erb create app/views/todos/new.html.erb create app/views/todos/_form.html.erb create app/views/todos/_todo.html.erb invoke resource_route invoke test_unit create test/controllers/todos_controller_test.rb invoke helper create app/helpers/todos_helper.rb invoke test_unit invoke jbuilder create app/views/todos/index.json.jbuilder create app/views/todos/show.json.jbuilder create app/views/todos/_todo.json.jbuilder

bin/rails db:migrate

== 20261105004223 CreateTodos: migrating ====================================== -- create_table(:todos) -> 0.0035s == 20261105004223 CreateTodos: migrated (0.0035s) =============================

The generated controller at app/controllers/todos_controller.rb handles all seven actions, and the generated views are the five files above plus two partials. The controller and view in the next two sections are simplified versions of those files, kept short enough to read; the output on this page is from the generated scaffold.

resources :todos expands to seven routes: index, show, new, create, edit, update and destroy. They share a controller and a set of URL helpers, which is the convention that keeps a Rails application predictable.

The controller

The generated controller has one method per action. The ones a reader meets first are index, show and create:

class TodosController < ApplicationController def index @todos = Todo.order(:created_at) end def show @todo = Todo.find(params[:id]) end def create @todo = Todo.new(todo_params) if @todo.save redirect_to @todo, notice: "Todo was created." else render :new, status: :unprocessable_entity end end private def todo_params params.require(:todo).permit(:title, :done) end end

params holds the path, the query and the form body. permit is the allow list: a parameter that is not listed never reaches the model, which is the protection against a form that posts an extra admin: true.

The view

The view is ERB: HTML with Ruby inside <% %>. The output tag is <%= %>, and the instance variable the controller set is available:

<h1>Todos</h1> <ul> <% @todos.each do |todo| %> <li><%= link_to todo.title, todo %></li> <% end %> </ul> <%= link_to "New todo", new_todo_path %>

link_to builds the path from the route helpers, so a change to the route changes every link. The generated views are a starting point: a real page replaces the markup and keeps the helpers.

bin/rails server

=> Booting Puma => Rails 8.1.4.1 application starting in development => Run `bin/rails server --help` for more startup options Puma starting in single mode... * Puma version: 8.0.2 ("Into the Arena") * Ruby version: ruby 3.4.12 (2026-10-23 revision 366f5fdc00) +PRISM [x86_64-linux] * Min threads: 3 * Max threads: 3

The server listens on 3000. The index page the scaffold wrote renders the heading and an empty list, because the table is empty:

curl -s localhost:3000/todos

<h1>Todos</h1> <div id="todos"> </div>

The development log prints the SQL, the template and the timing of each request, which is the first place to look when a page is slow.

What to watch for

Rails is convention over configuration: a file in the wrong folder is loaded late or not at all. The error usually names the constant and the folder the framework looked in.

A scaffold is a teaching tool, not a design. It writes views and controller actions a real app replaces within a week; keep the migration, the model and the routes, and rewrite the rest.

Next: A JSON API in Rails

Article author: Arthur Isaev