What is Model-View-Controller (MVC) in Ruby on Rails?
Model-View-Controller (MVC) is a design pattern that separates the application logic into three interconnected components. This pattern helps in organizing the code in a clean and maintainable way. In this blog, we will explore the MVC pattern, its components, and how it is used in Ruby on Rails, a popular web development framework.
1. Introduction to MVC
When learning programming, it's essential to write clean and organized code. It makes the code easier to understand, maintain, and extend. One way to achieve this is by using design patterns. A design pattern is a reusable solution to common problems that occur in software design. One such design pattern is the Model-View-Controller (MVC).
Imagine you are building a web application to manage a library. The application allows users to search for books, view book details, and reserve books. To build this application, you need to handle data (books, authors, etc.), display the information in a user-friendly way, and respond to user actions (searching, reserving, etc.). These concerns can be separated into three components: Model, View, and Controller.
2. Model
The Model is responsible for managing the application's data and business logic. It represents the underlying structure of the data and defines how it should be stored, retrieved, and manipulated. The Model also enforces the application's rules and constraints.
For our library application, the Model would represent the books, authors, and reservations. It would define how books are added, searched, and reserved.
Here's a simple example of a Book model in Ruby:
class Book
attr_accessor :title, :author, :status
def initialize(title, author, status = "available")
@title = title
@author = author
@status = status
end
def reserve
if @status == "available"
@status = "reserved"
true
else
false
end
end
def return_book
if @status == "reserved"
@status = "available"
true
else
false
end
end
end
In this example, the Book
class has three attributes: title
, author
, and status
. It also has two methods: reserve
and return_book
. These methods enforce the rules for reserving and returning books.
3. View
The View is responsible for presenting the data to the user. It defines how the information should be displayed and formatted. The View is also responsible for receiving user input and passing it to the Controller.
For our library application, the View would display the list of books, book details, and reservation forms. It would also handle user input, such as searching for a book or reserving a book.
Here's an example of a simple View for displaying a list of books in HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Library</title>
</head>
<body>
<h1>Books</h1>
<ul>
<% books.each do |book| %>
<li><%= book.title %> by <%= book.author %></li>
<% end %>
</ul>
</body>
</html>
In this example, the View uses Ruby's ERB (Embedded Ruby) to loop through an array of Book
objects and display their title and author in an unordered list.
4. Controller
The Controller is responsible for coordinating the Model and View. It receives user input from the View, processes it, updates the Model, and updates the View with the new data. The Controller acts as a bridge between the Model and View, ensuring that they remain separate and focused on their specific responsibilities.
For our library application, the Controller would handle user actions such as searching for a book, viewing book details, and reserving a book. It would update the Model with the results of these actions and update the View to display the new information.
Here's an example of a simple Controller for our library application in Ruby:
class LibraryController
def index
@books = Book.all
render "index"
end
def search(query)
@books = Book.search(query)
render "search_results"
end
def reserve(book_id)
book = Book.find(book_id)
if book.reserve
render "reserve_success"
else
render "reserve_failure"
end
end
end
In this example, the LibraryController
has three methods: index
, search
, and reserve
. Each method retrieves or updates data through the Book model, and then renders a corresponding View to display the results.
5. MVC in Ruby on Rails
Ruby on Rails is a web development framework that follows the MVC pattern. Rails provide conventions and tools for organizing your code into Models, Views, and Controllers, making it easy to build clean and maintainable web applications.
In Rails, each component of the MVC pattern has a specific folder:
- Models are stored in the
app/models
folder. - Views are stored in the
app/views
folder, organized by controller. - Controllers are stored in the
app/controllers
folder.
Let's see how our library application would be structured in Ruby on Rails.
Model
To create a Book
model in Rails, you would use the following command:
rails generate model Book title:string author:string status:string
This command generates a Book
model with title
, author
, and status
attributes. The model file would look like this:
# app/models/book.rb
class Book < ApplicationRecord
end
You can add custom methods (like reserve
and return_book
) to the model:
# app/models/book.rb
class Book < ApplicationRecord
def reserve
if self.status == "available"
self.update(status: "reserved")
true
else
false
end
end
def return_book
if self.status == "reserved"
self.update(status: "available")
true
else
false
end
end
end
View
In Rails, Views are organized by controller. For our library application, we would create a books
folder inside the app/views
folder. Then, we would create a file called index.html.erb
to display the list of books:
<!-- app/views/books/index.html.erb -->
<h1>Books</h1>
<ul>
<% @books.each do |book| %>
<li><%= book.title %> by <%= book.author %></li>
<% end %>
</ul>
Controller
To create a BooksController
in Rails, you would use the following command:
rails generate controller Books
This command generates a BooksController
with a default index
method. You can add the search
and reserve
methods to the controller:
# app/controllers/books_controller.rb
class BooksController < ApplicationController
def index
@books = Book.all
end
def search
@books = Book.where("title ILIKE ?", "%#{params[:query]}%")
end
def reserve
@book = Book.find(params[:id])
if @book.reserve
redirect_to @book, notice: "Book was successfully reserved."
else
redirect_to @book, alert: "Book could not be reserved."
end
end
end
In this example, the BooksController
retrieves and updates data through the Book
model and renders the corresponding Views.
6. Conclusion
In this blog, we explored the Model-View-Controller (MVC) design pattern and how it is used in Ruby on Rails. By separating the application into Models, Views, and Controllers, the MVC pattern helps you write clean, organized, and maintainable code.
When building web applications, following design patterns like MVC can make a significant difference in the long run. It allows you to focus on individual components without becoming overwhelmed by the complexity of the entire application. So, keep practicing, and always strive to write clean and organized code. Happy coding!