
Understanding rails basic CoC under scaffold for beginners
Rails is a framework where almost everything is based on convention over configuration (CoC) philosophy. Many beginners with rails framework don’t understand exactly what rails do with CoC to build applications.
This is a tutorial for beginners only, if you’re not new in ruby/rails development, close this tab, I will explain exactly what rails do on a basic CRUD flow based on what rails do when creating a scaffold.
The code used at this tutorial can be found here.
Creating the example
First of all, create and rails application with any name, In this tutorial, I will use the library (With sqlite because of its don’t matter here).
rails new library
(If you usually read my blog, at this point you already realized that I use library example on every tutorial, I will use other examples on my next tutorial, I promise)
Now, you’re with a new application without any controller or model (except application).
Our focus on this tutorial will be on the interaction between model-view-controller while creating a simple CRUD.
At this time, rails already created all project structure and our folders are this:
app
├── assets
├── channels
├── controllers
│ ├── application_controller.rb
│ └── concerns
│ └── .keep
├── models
│ ├── application_record.rb
│ └── concerns
│ └── .keep
└── views
└── layouts
├── application.html.erb
├── mailer.html.erb
└── mailer.text.erb
In my opinion the most simple way to understanding and see what rails do with CoC philosophy is using simple rails command-line tools and see what files rails create and where.
rails g scaffold book isbn:string name:string author:string description:text
Rails will output something like this:
invoke active_record
create db/migrate/20171225225129_create_books.rb
create app/models/book.rb
invoke test_unit
create test/models/book_test.rb
create test/fixtures/books.yml
invoke resource_route
route resources :books
invoke scaffold_controller
create app/controllers/books_controller.rb
invoke erb
create app/views/books
create app/views/books/index.html.erb
create app/views/books/edit.html.erb
create app/views/books/show.html.erb
create app/views/books/new.html.erb
create app/views/books/_form.html.erb
invoke test_unit
create test/controllers/books_controller_test.rb
invoke helper
create app/helpers/books_helper.rb
invoke test_unit
invoke jbuilder
create app/views/books/index.json.jbuilder
create app/views/books/show.json.jbuilder
create app/views/books/_book.json.jbuilder
invoke test_unit
create test/system/books_test.rb
invoke assets
invoke coffee
create app/assets/javascripts/books.coffee
invoke scss
create app/assets/stylesheets/books.scss
invoke scss
create app/assets/stylesheets/scaffolds.scss
Understading what rails do with Scaffold
- Newsletter 36 – 02/2023A curated lists of the best things that I’ve read last month. Issue February2023.
At this time, let’s look carefully at everything that rails do on the last command, starting with first lines.
invoke active_record
create db/migrate/20171225225129_create_books.rb
create app/models/book.rb
invoke test_unit
create test/models/book_test.rb
create test/fixtures/books.yml
Rails invoked an active record to generate a migration file with the fields that we specified on scaffold command and created a model book and a test for him.
invoke resource_route
route resources :books
On the next lines (the above lines), rails created resources routes for books.
Resource routing allows you to quickly declare all of the common routes for a given resourceful controller. Instead of declaring separate routes for your index, show, new, edit, create, update and destroy actions, a resourceful route declares them in a single line of code. See more: http://guides.rubyonrails.org/routing.html#resource-routing-the-rails-default
If you understood what resources do at routes you already realized that rails will search for a controller named book when receiving a request for /books, and that is exactly what rails created on the next steps of scaffold:
invoke scaffold_controller
create app/controllers/books_controller.rb
But if you open this file, you will see a complete controller with all methods that resources do.
class BooksController < ApplicationController
before_action :set_book, only: [:show, :edit, :update, :destroy]
# GET /books
# GET /books.json
def index
@books = Book.all
end
# GET /books/1
# GET /books/1.json
def show
end
# GET /books/new
def new
@book = Book.new
end
# GET /books/1/edit
def edit
end
# POST /books
# POST /books.json
def create
@book = Book.new(book_params)
respond_to do |format|
if @book.save
format.html { redirect_to @book, notice: 'Book was successfully created.' }
format.json { render :show, status: :created, location: @book }
else
format.html { render :new }
format.json { render json: @book.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /books/1
# PATCH/PUT /books/1.json
def update
respond_to do |format|
if @book.update(book_params)
format.html { redirect_to @book, notice: 'Book was successfully updated.' }
format.json { render :show, status: :ok, location: @book }
else
format.html { render :edit }
format.json { render json: @book.errors, status: :unprocessable_entity }
end
end
end
# DELETE /books/1
# DELETE /books/1.json
def destroy
@book.destroy
respond_to do |format|
format.html { redirect_to books_url, notice: 'Book was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_book
@book = Book.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def book_params
params.require(:book).permit(:isbn, :name, :author, :description)
end
end
And this is part of rails scaffold magic, he generates the code of the controller, and this only works because of CoC that rails implements.
At this point, we already have the model and Controller, and on the next lines of the scaffold, we will have the views, completing the MVC design.
invoke erb
create app/views/books
create app/views/books/index.html.erb
create app/views/books/edit.html.erb
create app/views/books/show.html.erb
create app/views/books/new.html.erb
create app/views/books/_form.html.erb
At this point, rails created all the views that correspond for each action of the books controller, following the specified convention.
Rails documentation of action view for better understanding:
“There is a naming convention for views in Rails. Typically, the views share their name with the associated controller action, as you can see above. For example, the index controller action of the articles_controller.rb will use the index.html.erb view file in the app/views/articles directory. The complete HTML returned to the client is composed of a combination of this ERB file, a layout template that wraps it, and all the partials that the view may reference. Within this guide, you will find more detailed documentation about each of these three components. See more: http://guides.rubyonrails.org/action_view_overview.html”
Now, everything is done, we have the complete MVC. If you start your applications (you’ll need to run your migrations) and go to `http://localhost:3000/books` you can interact with our scaffold.
Your application should look like this:

(Note that I already added one book)
How rails pass information between controller-gview using CoC
Follow my blog:
But how everything works? How the information pass between the application? Let`s see this.
For this, we will use a legendary method called debug, first of all, add gem byebug at your gemfile.
gem 'byebug', '~> 9.0', '>= 9.0.6'
After this, run bundle at your project folder, wait and let`s debug.
For this test, we will use the index page of books.
But how to find where we can put our byebug? So, run rake routes at your project and you`ll see:
Prefix Verb URI Pattern Controller#Action
books GET /books(.:format) books#index
POST /books(.:format) books#create
new_book GET /books/new(.:format) books#new
edit_book GET /books/:id/edit(.:format) books#edit
book GET /books/:id(.:format) books#show
PATCH /books/:id(.:format) books#update
PUT /books/:id(.:format) books#update
DELETE /books/:id(.:format) books#destroy
Now you can see that when we access our application on /books we are redirected to book controller at index action. So, when we need to put our byebug? Exact, on books controller at index action.
class BooksController < ApplicationController
before_action :set_book, only: [:show, :edit, :update, :destroy]
# GET /books
# GET /books.json
def index
byebug
@books = Book.all
end
Now access our application at /books and go to terminal window when our server is running and we’ll see:
6: def index
7: byebug
=> 8: @books = Book.all
9: end
Now, on this line, we’re selecting all books using Active Record Book.all and storing at @books variable.
At this point @books is storing all books of my application in a ActiveRecord::Relation (But this don’t matter on this tutorial).
#<ActiveRecord::Relation [#<Book id: 1, isbn: "978-1400096237", name: "The Information", author: "James Gleick", description: "A nice book", created_at: "2017-12-27 19:18:01", updated_at: "2017-12-27 19:21:32">]>
But it’s only this, why are we storing this at @books? Where rails calls the view? Simple, fallowing the convention, our action is books controller, index action (fallowing what are in routes books#index) so rails will search for the view at app/views/books/index.html.erb and automatically starts it passing the @books variable that we created on controller.
So, open the books#index view file, and note that on some line (16 at my rails version), the generated code is accessing @books that we created on controller and using each loop.
<tbody>
<% @books.each do |book| %>
<tr>
<td><%= book.isbn %></td>
<td><%= book.name %></td>
<td><%= book.author %></td>
<td><%= book.description %></td>
<td><%= link_to 'Show', book %></td>
<td><%= link_to 'Edit', edit_book_path(book) %></td>
<td><%= link_to 'Destroy', book, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
Now if you put another byebug before our loop:
....
<% byebug %>
<% @books.each do |book| %>
<tr>
....
And make a new request, and wait for stop at this byebug:
17: <% byebug %>
=> 18: <% @books.each do |book| %>
19: <tr>
And calls for @books variable, we’ll see the the same data at variable (obviously).
<ActiveRecord::Relation [#<Book id: 1, isbn: "978-1400096237", name: "The Information", author: "James Gleick", description: "A nice book", created_at: "2017-12-27 19:18:01", updated_at: "2017-12-27 19:21:32">]>
And that’s is how rails pass data between the controller-view. For a better example I will create a new variable with my name at books#index:
def index
@books = Book.all
@name = 'Octos'
end
And I’ll add a new <h2> with this variable at view:
<h1>Books</h1>
<h2><%= @name %></h2>
And make a new request, and I’ll see my name at index because the rails pass the information of @name between the controller-view.

Disclaimer: The variable of controller and view is not the same, you can see this putting two byebugs, one on the controller and another at the view and calling the `object_id` on each, the numbers will be different.
Controller:
(byebug) @books.object_id
8
View:
(byebug) @books.object_id
70132622813300
Finishing
Everything is done, if you have any question, please ask.
The code of the example can be found here.
That’s all for today folks, don’t forget to follow my blog and my twitter.