RoR MVC Pattern
MVC stands for Model, View, Controller. It is the architectural pattern that Rails uses to organize your code. Every file you create in a Rails app fits into one of these three categories. Understanding MVC is the single most important concept in Rails.
The Core Idea: Separation of Concerns
MVC separates your app into three distinct jobs. Each part handles one responsibility and does not interfere with the others.
MVC: Three Rooms, One House +------------------+ +------------------+ +------------------+ | | | | | | | MODEL | | VIEW | | CONTROLLER | | | | | | | | Talks to the | | Shows HTML to | | Receives the | | database | | the user | | browser request | | | | | | | | Validates data | | Displays what | | Decides what | | | | the controller | | to do | | Stores business | | sends it | | | | logic | | | | Asks model for | | | | No data logic | | data, sends to | | No HTML | | here | | view | +------------------+ +------------------+ +------------------+
A Real-World Analogy: The Library
You (Browser) walks into a library and asks:
"I want to see all books about cooking."
|
v
Librarian (Controller)
- Receives your request
- Understands what you want
- Asks the catalog system for cooking books
|
v
Catalog System (Model)
- Searches the database
- Returns a list of cooking books
|
v
Librarian (Controller)
- Gets the list from the catalog
- Prepares it for display
|
v
Display Board (View)
- Shows the list of books to you
- Formatted, readable, no raw data
|
v
You (Browser) sees the final result
How MVC Works in Rails — Step by Step
Here is a concrete example. A user visits http://localhost:3000/posts to see all blog posts.
Step 1: Router receives the request
config/routes.rb get "/posts", to: "posts#index" Browser visits /posts → Router reads this line → Send this request to PostsController, action: index
Step 2: Controller runs
app/controllers/posts_controller.rb
class PostsController < ApplicationController
def index
@posts = Post.all ← asks the Model for all posts
end
end
Step 3: Model fetches data
app/models/post.rb (inherits from ApplicationRecord which connects to the database) Post.all → Runs: SELECT * FROM posts → Returns: array of post objects
Step 4: View displays results
app/views/posts/index.html.erb <h1>All Posts</h1> <% @posts.each do |post| %> <h2><%= post.title %></h2> <p><%= post.body %></p> <% end %>
The @posts variable (set in the controller) is available in the view. The view loops through each post and displays it as HTML.
Step 5: Browser receives the HTML
Rails combines the view template with the data and sends a complete HTML page back to the browser. The user sees the list of posts.
The @ Symbol: Passing Data from Controller to View
Instance variables (variables starting with @) are the bridge between the controller and the view.
Controller sets: @posts = Post.all View accesses: @posts.each do |post| ... Controller sets: @user = User.find(1) View accesses: @user.name Controller sets: @message = "Welcome back!" View accesses: <%= @message %>
Regular local variables (without @) in the controller do NOT reach the view. Only instance variables do.
What Each Part Can and Cannot Do
| MVC Part | Can Do | Should NOT Do |
|---|---|---|
| Model | Query database, validate data, run calculations | Generate HTML, handle HTTP requests |
| View | Display data, format HTML, loop through arrays | Query database directly, contain business logic |
| Controller | Receive requests, call models, pass data to views | Write complex queries, contain display logic |
Fat Model, Skinny Controller
Rails developers follow a rule called "Fat Model, Skinny Controller." It means: put complex logic in the model, keep the controller simple.
BAD — Logic in controller (too fat): def index @active_users = User.where(active: true).order(:name).limit(10) @total_revenue = Order.sum(:amount) * 0.9 end GOOD — Logic in model (skinny controller): def index @active_users = User.active_list ← method defined in User model @total_revenue = Order.net_revenue ← method defined in Order model end
The controller above is easy to read. The logic lives in the model where it can be tested and reused.
Why MVC Makes Your Code Better
- Easier to find bugs — you know exactly which file to look at for each type of problem
- Easier to work in teams — one developer works on views while another works on models
- Easier to test — each part can be tested independently
- Easier to grow — adding a new feature follows the same structure every time
MVC is not unique to Rails. Django, Laravel, and ASP.NET all use it. Once you understand MVC in Rails, you can quickly learn any other MVC framework.
