Model-View-Controller in Ruby on Rails
Ruby on Rails, is a powerful web application framework that embraces the Model-View-Controller (MVC) design pattern. If you're just starting your Rails journey, understanding MVC is crucial because it defines how your application is structured and how its components interact with one another.
In this post, we'll break down MVC using a simple project example: Store app with Product and Category models. This example demonstrates Rails' ability to handle data, views, and user interactions seamlessly.
What is MVC?
MVC stands for:
- Model: Represents the data and the business logic of your application. In Rails, models handle database interactions.
- View: Displays the data to the user. Views in Rails are typically written in HTML with embedded Ruby (ERB) or other templating engines.
- Controller: Handles user input and updates the model or view accordingly. Controllers act as the middleman between models and views.
Rails automatically organizes these components into separate directories: app/models
,
app/views
, and
app/controllers
.

In the official Ruby on Rails Guide, you can find detailed explanations about all the aspects. Here, we will discuss a simpler example to familiarize ourselves with the MVC pattern.
Let's create a basic Rails app called Store:
$ rails new store
And see how each MVC component plays a role.
The Model
The model represents the application's data. In our Store app, we'll define two models:
and Product
.Category
Run these commands to generate the models:
$ rails generate model Category name:string description:text
$ rails generate model Product name:string price:decimal category:references
Rails will create database migrations and model files for you. Note that rails generators use the parameters (name:string description:text
) that create database columns with specific types. You can see and edit them in the migration files (read more about Active Record Migration files).
After generating the models, run the migrations to update the database:
$ rails db:migrate
Define associations between models:
# app/models/category.rb
class Category < ApplicationRecord
has_many :products
end
# app/models/product.rb
class Product < ApplicationRecord
belongs_to :category
end
The Controller
The controller connects user input with the model and view. Let’s create a
and a ProductsController
to handle requests.CategoriesController
Generate the controllers:
$ rails generate controller Products
$ rails generate controller Categories
Add basic actions for the
:ProductsController
# app/controllers/products_controller.rb
class ProductsController < ApplicationController
def index
@products = Product.all
end
def show
@product = Product.find(params[:id])
end
def new
@product = Product.new
end
def create
@product = Product.new(product_params)
if @product.save
redirect_to @product, notice: 'Product was successfully created.'
else
render :new
end
end
private
def product_params
params.require(:product).permit(:name, :price, :category_id)
end
end
The View
The view displays data to the user. Rails’ convention automatically looks for view templates matching controller actions, such as
or index
.show
Create a file for the
action:index
<!-- app/views/products/index.html.erb -->
<h1>Products</h1>
<ul>
<% @products.each do |product| %>
<li>
<%= link_to product.name, product_path(product) %> — $<%= product.price %>
</li>
<% end %>
</ul>
<%= link_to 'Add a Product', new_product_path %>
And for the
action:show
<!-- app/views/products/show.html.erb -->
<h1><%= @product.name %></h1>
<p>Price: $<%= @product.price %></p>
<p>Category: <%= @product.category.name %></p>
<%= link_to 'Back to Products', products_path %>
Note, that in this example we use instance variables in the views (they starts with @
sign).
Routes
Define routes for
and products
:categories
# config/routes.rb
Rails.application.routes.draw do
resources :products
resources :categories
end
How MVC Works Together
Here’s what happens when a user visits the
page:/products
- Router: The request is routed to the
action.ProductsController#index
- Controller: The
action fetches all products from the database and assigns them toindex
.@products
- View: The corresponding
file displays the list of products.index.html.erb
- Model: If data needs to be updated (e.g. during
create
orupdate
action), the model handles database interactions.
Conclusion
Understanding MVC is the foundation of Rails development. By dividing your app into models, views, and controllers, Rails makes it easy to build and maintain web applications. As you grow, you’ll explore advanced features like validations, callbacks, and associations.
Start experimenting with your app and see how each component of MVC works to create a seamless experience for developers and users.
Stay tuned! In my upcoming posts, I want to explain how to quickly build CRUD Applications with generators and make the styling better with Tailwind CSS.