View on Github
Ruby Rails MVC Architecture ActiveRecord RESTful Routing
To-do App Project Showcase
I built a simple Todo app using Ruby on
Rails.
The main goals were to grasp basic Rails concepts,
handle CRUD operations (Create, Read, Update, Delete),
and make use of the MVC architecture, ActiveRecord, and RESTful routing.
This blog post breaks down the project, highlighting how these elements work together to create an
effective and easy-to-use Todo application.
Contents
- Why I chose Ruby on Rails
- The Model-View-Controller (MVC) Architecture
- RESTful Routing
- Challenges Faced and Lessons Learned
- Conclusion
1. Why I chose Ruby on Rails
I chose Ruby on Rails for these reasons:
- Powerful Framework: Ruby on Rails is a powerful and versatile web development framework, and is known for its productivity and community support. Major platforms like GitHub and Airbnb are built on it.
- Skill Expansion: After working with Flask and MERN stack, I wanted to expand my skills by diving into a new language and framework.
- Learning from Experience: Revisiting an old Node.js project (link to the old repo), I aimed to transform a basic todo list into a whole-stack Rails app, so that I can showcase my growth in my development path.
2. The Model-View-Controller (MVC) Architecture
The backbone of my Todo app lies in the Model-View-Controller (MVC) architecture, a design pattern
that is important for developing scalable, efficient and maintainable web applications.
Model
Rails uses ActiveRecord, an ORM
(Object-Relational
Mapping) system to integrate with the Model,
providing an intuitive way to interact with the database. For this app I used two models - the
`Todo`
model and the `Item`
model.
1. Todo Model (Category):
The `Todo`
model represents our categories and defines the relationship with the
`Item`
model,
establishing a one-to-many association. This association allows a single category to have
multiple
tasks. For example, a `todo`
record can be `Grocery`
. Under
`Grocery`
there can be multiple items,
like `beef`
, `onion`
, etc.
Here's what the `Todo` model looks like:
Image: `models/todo.rb`
The `has_many :items`
association establishes a connection between the
`Todo`
and `Item`
models, and
the `dependent: :destroy`
option ensures that when a category is deleted, all
associated tasks (items) are also destroyed.
Below is an example:
GIF: When Study Python is deleted, all items inside are also deleted.
2. Item Model (Task):
The `Item`
model represents individual tasks and belongs to a category
(`Todo`
).
It also includes a `before_save`
callback to set a default value for the
`done`
attribute.
Here's what the `Item` model looks like:
Image: `models/item.rb`
The `belongs_to :todo`
association establishes the connection between the
`Item`
and `Todo`
models, indicating that each task belongs to a specific
category.
View
Responsible for presenting the data to the users and capturing their interactions, views are implemented using HTML and embedded Ruby (ERB) templates. These templates dynamically render the data from the controller and provide a user-friendly interface for my Todo app.
`render` vs `redirect_to`
When it comes to rendering views and managing user interactions,
Rails provides two key methods: `render`
and `redirect_to`
.
I used the `render`
method to dynamically generate HTML content based on the ERB
templates. This
allowed me to present data from the controller to the user without a full page reload. For instance,
when a form failed to be saved, you want to update the error message but don’t want to lose all the
fields the user has already typed in:
GIF: When a form is failed to saved, the existing form input (i.e. description) is not erased.
On the other hand, the `redirect_to`
method is useful in managing user navigation and
handling actions such as creating, updating, or deleting tasks. For example, after creating a new
category:
GIF: The page is redirected to show the todo page we just created.
It’s important to know the difference because `render`
will pass to the view the same
parameters but `redirect_to`
will send a completely new request to the browser.
Partials
For a more maintainable and DRY (Don't Repeat Yourself) codebase, I embraced the use
of partials in
our views.
Partials are reusable snippets of ERB templates that can be included in other views.
For instance, I created a `_form.html.erb`
partial for both the `Todo`
and
`Item`
views to render their respective forms.
Here's a snippet of the `Item` form partial:
Image: Partials - rendering a particular piece of a response to its own file.
Utilizing partials not only simplified the view files but also promoted consistency and reusability across different parts of the application.
Controller
Responsible for handling user requests, Controllers are stored in the `app/controllers`
directory.
Acting as an intermediary between the Model and View, controllers
handle user input, processes it,
and updates the Model accordingly. My `TodosController`
and
`ItemsController`
manage CRUD operations
for Todo items, ensuring the seamless flow of data between the Model and View.
For instance, when a user adds a new task or marks one as complete, the Controller manages these
actions, ensuring that the Model and View remain synchronized.
Todo Controller:
Image: Todo Controller
In the `TodosController`
, I handle actions such as displaying all categories
(`index`
),
showing a specific category (`show`
), creating a new category (`new`
and
`create`
), editing an existing category (`edit`
and
`update`
), and deleting a category (`destroy`
). Each action corresponds to
a specific view, and the controller ensures that the correct view is rendered or redirected based on
the user's interactions.
Item Controller:
Image: Item Controller
In the `ItemsController`
, I handle actions for creating (`create`
),
updating (`update`
), and deleting
(`destroy`
) tasks. The `create`
action redirects to the associated
category's show page after
creating a task, and the `update`
and `destroy`
actions also redirect to
the category's show page
after completing their respective operations.
The MVC architecture not only enhanced the structure of the Todo app but also contributed
significantly to its maintainability, scalability, and overall
development efficiency.
3. RESTful Routing
RESTful routing is an important concept in Ruby on Rails that defines the way web applications handle
HTTP requests. In Ruby on Rails, RESTful routing is built around the idea of
treating each component
of a web application as a resource, represented by a specific URL
path. These resources are
manipulated using standard HTTP methods, such as `GET`
, `POST`
,
`PUT`
/`PATCH`
, and `DELETE`
, which correspond
to CRUD (Create, Read, Update, Delete) operations. This approach provides a uniform
and clear
process of designing and maintaining web applications.
Let's delve into the `config/routes.rb`
file of my Todo app.
Image: `config/routes.rb` file
-
The default landing page is the root route (
`/`
) that points to the`index`
action of the`TodosController`
, displaying a list of all todo categories. - The custom route (
`/about`
) is mapped to the`/about`
action of the`ApplicationController`
, providing a dedicated page for information about your application. `resources :todos`
generates RESTful routes for the`Todo`
resource, automatically creating routes for the actions`index`
,`new`
,`create`
,`edit`
,`update`
,`show`
, and`destroy`
.- Additionally, by nesting
`resources :items`
within`resources :todos`
, they established a hierarchical relationship, allowing the routes to relate the`items`
within a specific`todo`
.
Integration with Controllers
Each route defined in `config/routes.rb`
corresponds to an action in a controller. For example, when a user accesses the root URL (/), the `index`
action of the `TodosController`
is triggered. Similarly, when they visit `/todos/new`
, the `new`
action is called, allowing for the creation of new todo items.
Let's take a closer look at the relationship between the routes and the controller actions:
`GET /todos`
maps to`TodosController#index`
: Displays a list of all todo items.`GET /todos/:id`
maps to`TodosController#show`
: Displays details of a specific category and all items created under it.
GIF: `GET /todos` and `GET /todos/:id`
And for nested resources:
`POST /todos/:todo_id/items`
maps to`ItemsController#create`
: Add a new item under a specific todo category.`PATCH /todos/:todo_id/items/:id`
maps to`ItemsController#update`
: Update an item’s status to be done or undone.
GIF: `POST /todos/:todo_id/items`: Create item Dictionary under todo category Study Python
GIF: `PATCH /todos/:todo_id/items/:id`: Toggle item status between done and undone
4. Challenges-Faced-and-Lessons-Learned
In all honesty, developing a Todo app might seem like a straightforward project, and I didn't
encounter major obstacles. Most of the concepts, such as routing and MVC, were already familiar to
me from previous frameworks I've worked with, like MERN stack applications.
However, if I were to highlight a challenge, it would be my first experience to the Ruby language
itself. As this was my first non-trivial application in Ruby, I invested some time learning the
language before even delving into Rails. This included mastering the basics,
understanding
object-oriented programming (OOP) concepts, and gaining proficiency in file
handling and
serialization in Ruby. I even practiced those concepts in ruby through projects like Mastermind, Tic-Tac-Toe,
and Hangman (links are the
github repos to them). As a result, completing this Todo app project significantly enhanced my
familiarity and comfort with the Ruby language.
The second noteworthy challenge was adapting to the Rails framework and its principle of
`convention
over configuration`. Learning to use Rails was a bit tricky. I had to spend a good
amount of time
reading the guides and documentation to understand how things
work. Even though it took some effort,
what I learned turned out to be super useful and a great investment. It has become the building
blocks for me in being a proficient and confident developer in Rails.
5. Conclusion
In this post, we have explored the key Rails concepts within my Todo app project, including the
MVC architecture, ActiveRecord, and RESTful routing.
These concepts are important in building robust and scalable web applications because they provide a
structured way to organize code, interact with databases coherently, and define logical and
user-friendly routes. As I look forward to future projects, I am excited about the continued
learning and expanding my skills in the world of Ruby on Rails.
You've just finished reading: To-do App Project Showcase