While you’re developing Rails applications, especially those which are mainly providing you with a simple interface to data in a database, it can often be useful to use the scaffold method.
Scaffolding provides more than cheap demo thrills. Here are some benefits −
- You can quickly get code in front of your users for feedback.
- You are motivated by faster success.
- You can learn how Rails works by looking at the generated code.
- You can use scaffolding as a foundation to jump start your development.
To understand scaffolding, let’s start by creating a new Rails application named cookbook. It will have database called cookbook and a table called recipes.
Creating an Empty Rails Web Application
Open a command window and navigate to where you want to create this cookbook web application and run the following command to create a complete project structure.
rails new cookbook
Rails uses SQLite as the default database. To specify other database type, use -d option. For example, the following command creates a Rail application with mysql as its backend database.
rails new cookbook -d mysql
Rails supports PostgreSql, Oracle, SQL Server and Maria DB databases also.
By default, Rails includes importmaps for JavaScript, but you can choose a different frontend framework such as Webpack, Tailwind CSS, Bootstrap or ESBuild.
If you are using RubyMine IDE, the new project wizard lets you choose the database and the frontend framework.

Rails generates database.yml configuration file inside the config/ directory. It has the configuration for development as well as production environment.
default:&default adapter: sqlite3 pool:<%=ENV.fetch("RAILS_MAX_THREADS"){5}%> timeout:5000 development:<<:*default database: storage/cookbook.sqlite3 test:<<:*default database: storage/test.sqlite3 production: primary:<<:*defaultcache:<<:*defaultdatabase: storage/cookbook.sqlite3
queue:<<:*defaultdatabase: storage/production_cache.sqlite3 migrations_paths: db/cache_migrate
cable:<<:*defaultdatabase: storage/production_queue.sqlite3 migrations_paths: db/queue_migrate
database: storage/production_cable.sqlite3 migrations_paths: db/cable_migrate
If you specify -d option with mysql as the database, database.yml file must contain the database credentials.
development: adapter: mysql database: cookbook username: root password:[password] host: localhost test: adapter: mysql database: cookbook username: root password:[password] host: localhost production: adapter: mysql database: cookbook username: root password:[password] host: localhost
If you prefer to use MySQL or PostgreSQL, you will need to run the command:
rails db:create
Generated Scaffold Code
With the scaffold action, Rails generates all the code it needs dynamically. By running scaffold as a script, we can get all the code written to disk, where we can investigate it and then start tailoring it to our requirements.
Run the scaffold generator to create a Recipe model with title (string) and instructions (text):
rails g scaffold Recipe tittle:string instructions:text
The command prompt terminal (terminal in Ubuntu) shows the following log as different files are created:

This command creates:
- Model: app/models/recipe.rb
- Migration: db/migrate/ rb
- Controller: app/controllers/recipes_controller.rb
- Views: app/views/recipes/
- Routes: Updates config/routes.rb
Run the Migration
You can use Rails Migrations to create and maintain tables. Apply the migration to create the recipes table in MySQL:
rake db:migrateRAILS_ENV=development
The command terminal shows the following log:
rake db:migrateRAILS_ENV=development ==20250220120618CreateRecipes: migrating ====================================-- create_table(:recipes)->0.0026s ==20250220120618CreateRecipes: migrated (0.0035s)===========================
This will create the recipes table with the following structure:
CREATETABLE recipes (id INTEGERPRIMARYKEY AUTOINCREMENT NOTNULL, tittle VARCHAR, instructions TEXT, created_at DATETIME(6)NOTNULL, updated_at DATETIME(6)NOTNULL);</pre>
The Controller
Let's look at the code behind the controller. This code is generated by the scaffold generator. If you open app/controllers/recipes_controller.rb, then you will find something as follows
classRecipesController<ApplicationController before_action :set_recipe, only:%i[ show edit update destroy ]# GET /recipes or /recipes.jsondefindex@recipes=Recipe.all end# GET /recipes/1 or /recipes/1.jsondefshowend# GET /recipes/newdefnew@recipe=Recipe.newend# GET /recipes/1/editdefeditend# POST /recipes or /recipes.jsondefcreate@recipe=Recipe.new(recipe_params)respond_to do|format|[email protected] format.html { redirect_to @recipe, notice:"Recipe was successfully created."} format.json { render :show, status::created, location:@recipe}else format.html { render :new, status::unprocessable_entity} format.json { render json:@recipe.errors, status::unprocessable_entity}endendend# PATCH/PUT /recipes/1 or /recipes/1.jsondefupdate respond_to do|format|[email protected](recipe_params) format.html { redirect_to @recipe, notice:"Recipe was successfully updated."} format.json { render :show, status::ok, location:@recipe}else format.html { render :edit, status::unprocessable_entity} format.json { render json:@recipe.errors, status::unprocessable_entity}endendend# DELETE /recipes/1 or /recipes/[email protected]!
respond_to do|format| format.html { redirect_to recipes_path, status::see_other, notice:"Recipe was successfully destroyed."} format.json { head :no_content}endendprivate# Use callbacks to share common setup or constraints between actions.defset_recipe@recipe=Recipe.find(params.expect(:id))end# Only allow a list of trusted parameters through.defrecipe_params params.expect(recipe:[:tittle,:instructions])endend</pre>
When the user of a Rails application selects an action, e.g. "Show" - the controller will execute any code in the appropriate section - "def show" - and then by default will render a template of the same name - "show.html.erb". This default behavior can be overwritten.
The controller uses ActiveRecord methods such as find, find_all, new, save, update_attributes, and destroy to move data to and from the database tables. Note that you do not have to write any SQL statements, rails will take care of it automatically.
This single line of code will bring the database table to life. It will provide with a simple interface to your data, and ways of −
- Creating new entries
- Editing current entries
- Viewing current entries
- Destroying current entries
When creating or editing an entry, scaffold will do all the hard work like form generation and handling for you, and will even provide clever form generation, supporting the following types of inputs −
- Simple text strings
- Text areas (or large blocks of text)
- Date selectors
- Date-time selectors
Now, go to the cookbook directory and run the Web Server using the following command −
rails server
Now, open a browser and navigate to http://127.0.0.1:3000/recipes/new. This will provide you a screen to create new entries in the recipes table. A screenshot is shown below

Once you press the Create button to create a new recipe, your record is added into the recipes table and it shows the following result

You can see the option to edit, show, and destroy the records. So, play around with these options.

Enhancing the Model
Rails gives you a lot of error handling for free. To understand this, add some validation rules to the empty recipe model −
Modify app/models/recipe.rb as follows and then test your application −
classRecipe<ActiveRecord::Base validates_length_of :title,:within=>1..20 validates_uniqueness_of :title,:message=>"already exists"end
These entries will give automatic checking.
- validates_length_of − the field is not blank and not too long.
- validates_uniqueness_of − duplicate values are trapped. Instead of the default Rails error message, we have given a custom message here.
The Views
All the views and corresponding all the controller methods are created by scaffold command and they are available in the app/views/recipes directory.
How Scaffolding is Different?
Although we can manually create the methods to list, show, delete and create data etc., but scaffolding does that job automatically.
Leave a Reply