The MVC Pattern in Rails

· 4 min read · Updated March 7, 2026 · beginner
mvc rails models views controllers architecture beginner

MVC stands for Model-View-Controller, and it’s the architectural pattern that powers every Rails application. Understanding MVC is essential for building maintainable Rails apps. In this tutorial, you’ll learn what each layer does and how they communicate.

What is MVC?

MVC divides your application into three interconnected components:

  • Model — Handles data and business logic
  • View — Handles presentation and user interface
  • Controller — Handles requests and coordinates between Model and View

This separation keeps your code organized and each part focused on one responsibility.

The Model Layer

The Model represents your data and the rules that govern it. In Rails, models typically interact with a database through ActiveRecord.

# app/models/article.rb
class Article < ApplicationRecord
  validates :title, presence: true
  validates :body, presence: true
  
  scope :published, -> { where(published: true) }
end

Models define relationships between data:

class Author < ApplicationRecord
  has_many :articles
end

class Article < ApplicationRecord
  belongs_to :author
end

The Model layer is where your business logic lives — validations, calculations, and database queries.

The View Layer

Views are what users see. They render the data from the Model into HTML, JSON, or other formats.

<!-- app/views/articles/show.html.erb -->
<h1><%= @article.title %></h1>

<p><%= @article.body %></p>

<%= link_to "Edit", edit_article_path(@article) %>

Views should contain minimal logic — just enough to display data. Complex logic belongs in the Model or Controller.

Rails supports multiple view formats:

# Respond with HTML or JSON based on the request
def show
  @article = Article.find(params[:id])
  
  respond_to do |format|
    format.html  # renders show.html.erb
    format.json { render json: @article }
  end
end

The Controller Layer

Controllers handle incoming requests, coordinate with Models, and return responses. They’re the bridge between the user and your application.

# app/controllers/articles_controller.rb
class ArticlesController < ApplicationController
  def index
    @articles = Article.published
  end
  
  def show
    @article = Article.find(params[:id])
  end
  
  def create
    @article = Article.new(article_params)
    
    if @article.save
      redirect_to @article, notice: "Article created!"
    else
      render :new, status: :unprocessable_entity
    end
  end
  
  private
  
  def article_params
    params.require(:article).permit(:title, :body, :published)
  end
end

Controllers should be thin — they coordinate between Model and View rather than containing business logic.

How MVC Works Together

Here’s the typical request flow in a Rails application:

  1. Request — User visits /articles/1
  2. Route — Rails routes GET /articles/:id to ArticlesController#show
  3. Controller — Controller asks Model for the data
  4. Model — Retrieves data from database
  5. Controller — Passes data to View
  6. View — Renders HTML with the data
  7. Response — Server sends HTML back to the browser

Example: A Complete Flow

# routes.rb
Rails.application.routes.draw do
  resources :articles
end
# articles_controller.rb
class ArticlesController < ApplicationController
  def index
    @articles = Article.published.order(created_at: :desc)
  end
end
<!-- app/views/articles/index.html.erb -->
<h1>Articles</h1>

<% @articles.each do |article| %>
  <article>
    <h2><%= article.title %></h2>
    <p><%= article.body.truncate(100) %></p>
  </article>
<% end %>
# article.rb (Model)
class Article < ApplicationRecord
  validates :title, presence: true
  
  def truncated_body
    body.truncate(100)
  end
end

Notice how each layer has a single responsibility:

  • Model manages data and provides helper methods
  • Controller handles the request flow
  • View focuses on presentation

When MVC Matters

Following MVC conventions makes your Rails app:

  • Maintainable — Each layer has a clear purpose
  • Testable — You can test each layer independently
  • Scalable — Adding features doesn’t require rewriting everything
  • Collaborative — Multiple developers can work on different layers

Common Mistakes to Avoid

Putting too much logic in controllers or views is a common pitfall:

# BAD: Logic in controller
def index
  @articles = Article.where("created_at > ?", 7.days.ago)
                     .where(published: true)
                     .order(created_at: :desc)
                     .limit(10)
end
# GOOD: Logic in model (or a query object)
# app/models/article.rb
class Article < ApplicationRecord
  scope :recent_published, -> { 
    where("created_at > ?", 7.days.ago)
      .where(published: true)
      .order(created_at: :desc)
      .limit(10)
  }
end

# Controller stays thin
def index
  @articles = Article.recent_published
end

Summary

The MVC pattern is the foundation of Rails architecture:

  • Model — Data and business logic (ActiveRecord)
  • View — Presentation layer (ERB, JSON, etc.)
  • Controller — Request handling and coordination

Each layer has a clear responsibility, making your code easier to maintain and test. Keep controllers thin, put logic in models, and use views primarily for display.

In the next tutorial, we’ll dive deeper into Rails routing and see how requests are mapped to controllers.