2024-12-19
Understanding Rails MVC Architecture - From Abstract Concepts to Hanshin Tigers
First, I will explain the overview of the MVC (Model-View-Controller) pattern as a general abstract concept in software architecture, then discuss the characteristics of MVC architecture in Rails, and promote understanding of MVC by contrasting both approaches.
Finally, I would like to apply MVC architecture to the Hanshin Tigers.
What is the MVC (Model-View-Controller) Pattern as an Abstract Concept
The Three Roles (Responsibilities) of MVC
- Model
- The part that handles the "data" and "business logic" of the application.
- Not only handles persistence responsibilities such as data retrieval, storage, and updates, but also implements domain rules (e.g., product price calculation, inventory management) and validation logic (e.g., input validation).
- The part that handles the perspective of "what to deal with (domain)."
- View
- The "appearance (UI) part" displayed to users.
- This includes HTML and template engines, GUI components for desktop applications, or JSON formatting when returning REST APIs.
- Responsible for data presentation (layout and formatting) and user input forms - purely "presentation" responsibilities.
- Controller
- The role of receiving user input (e.g., HTTP requests in web applications), calling appropriate Models for processing, and passing the results to Views.
- The part that controls the "flow."
- Example: When a user presses the "user registration" button → Controller receives the request, asks Model (User) to register user information → Model saves to DB → Controller receives the save result and renders the View to return, etc.
- Also handles screen transitions, routing distribution, parameter reception/preprocessing, and exception handling.
What Makes MVC Great
The biggest benefit is the ability to clarify application responsibilities. By clarifying responsibilities, component independence is guaranteed, leading to improved ease of division of labor, reusability, and maintainability through clear test targets.
MVC Architecture in Rails
MVC itself is merely a "way of thinking about role division," and how to implement it specifically (class structure, directory structure, whether to use ORM, template engine selection, etc.) varies by framework and project.
For example, Ruby/Rails MVC, Java/Spring MVC, PHP/Laravel MVC, Python/Django MTV (strictly speaking, close to MVC), etc. - even with the same MVC philosophy, implementations vary widely. Here, I'll touch on the specifics of MVC Architecture in the Rails context.
Rails (Ruby on Rails) emphasizes "Convention over Configuration" as a design philosophy, and the MVC structure also runs on established rails of "if you do this, it works this way." Below, I'll explain Rails-specific mechanisms and "Rails-style" MVC.
Model (Rails Case)
- ActiveRecord
- Rails Model layer is basically implemented by inheriting from ActiveRecord classes.
- Handles database mapping (ORM: Object-Relational Mapping), with table name to class name mapping and column to attribute mapping performed automatically.
- For example, just writing
class User < ApplicationRecord
links to theusers
table, andUser.find(1)
can retrieve record number 1.
- Declarative Description of Validation and Associations
- Standard practice is to write validations declaratively in Model classes like
validates :email, presence: true, uniqueness: true
. - Associations with other tables are also declared like
has_many :posts
/belongs_to :user
. - These declarations make DB schema integration and related model connections easy.
- Standard practice is to write validations declaratively in Model classes like
- Where to Place Business Logic
- Rails recommends "Fat Model, Skinny Controller."
- However, when it becomes too complex, it's common to split logic using Service objects, Domain Service objects, and Concerns. Rather than explicitly placing a Repository layer from the start, it's more common to handle this with ActiveRecord Scopes, query methods, and module division.
View (Rails Case)
- ERB (Embedded Ruby) Templates
- By default, Ruby code is embedded in
.html.erb
files to output HTML. - Directory structure like
app/views/controller_name/action_name.html.erb
automatically corresponds to routing, and when rendering from Controller, the corresponding View is rendered.
- By default, Ruby code is embedded in
- Other Template Engines Also Available
- Haml, Slim, Builder (for XML generation), and even incorporating React or Vue to partially write JSX/TSX are possible, but "Rails standard View = ERB" is the strong perception.
- Also, when using API mode to return JSON,
.jbuilder
templates orrender json:
can be used to build the View part with Ruby code.
- Layouts and Partials
- Define layouts applied to the entire application like
app/views/layouts/application.html.erb
, and useyield
to insert each action's template. - The mechanism to call partial templates (_header.html.erb, etc.) like
render 'header'
comes standard, providing high View reusability.
- Define layouts applied to the entire application like
Controller (Rails Case)
- Inheriting from ActionController::Base
- Create Controllers corresponding to each resource (e.g., User) like
app/controllers/users_controller.rb
, and define action methods (e.g., index, show, new, create, edit, update, destroy). - Writing
resources :users
in routing (config/routes.rb) automatically generates RESTful URL to Controller action mappings.
- Create Controllers corresponding to each resource (e.g., User) like
- Filters (before_action, after_action, etc.)
- Authentication checks and common preprocessing can be set declaratively like
before_action :authenticate_user!
. - This makes it easier to focus on "business logic and model calls" within each action.
- Authentication checks and common preprocessing can be set declaratively like
- Strong Parameters
- Parameter permission/restriction is defined on the controller side like
params.require(:user).permit(:name, :email)
. - This incorporates a mechanism to prevent mass assignment of unauthorized attributes.
- Parameter permission/restriction is defined on the controller side like
- How to Return Responses
- Writing
render :show
orredirect_to users_path
in actions automatically renders corresponding views or redirects to different URLs. - When returning JSON format, just writing
render json: @user
automatically performs serialization through ActiveModel::Serializers or Jbuilder.
- Writing
Conceptual Diagram Summary
Rearchitecting the Hanshin Tigers
I will apply the MVC concepts summarized so far to the Hanshin Tigers.
View Positioning
First, let's define the View positioning. What users (Hanshin Tigers fans) see are "stadium scenes," "player performances," and "cheering scenes." This corresponds to the "View" in MVC.
Controller and Model: Use Case 1
As a premise, heckling comes from Hanshin fans toward the View. While I won't deliberately touch on specific heckling content here, there are various types: simple cheering, encouraging words that inspire players, or malicious heckling that reduces player motivation. If this affects player performance and influences win/loss outcomes, the Hanshin Tigers application could be considered somewhat vulnerable. Therefore, let's prepare a Controller to handle heckling requests.
While there's room for discussion about what this Controller should be, let's consider the manager as the Controller for now.
All heckling requests to the View first transition to the manager Controller. Here, malicious requests are validated to prevent packets from flowing to players.
For constructive, encouraging heckling, the manager Controller calls PlayerService, formats request data as needed, and coordinates with players.
Furthermore, if the manager Controller judges that "players aren't functioning at all," it calls ScoutService to gather data for judging whether to "cut players at the end of this season" or "reinforce with alternative players." Player DB updates are also performed continuously in ScoutService.
Controller and Model: Use Case 2
Also, Hanshin Tigers fans become more heated during Giants games, creating a tense atmosphere where Hanshin and Giants fans are on the verge of conflict. It's important to prepare for potential brawl trouble requests.
Since this differs from heckling requests, let's prepare a separate Controller as a security Controller.
This security Controller checks the scale of fights and presence of injuries, validating and assessing urgency to determine what level of response is needed.
For example, for "light argument level," only local security guards stopping it would be sufficient. In other words, if the request is simple, only Controller processing is needed without Model coordination. If it becomes "full-scale violence with injuries," AmbulanceService is called to handle injured parties.
Also, if this spreads the image that "going to the stadium is scary," it could lead to decreased attendance and sales, so PublicRelationsService is called as needed to improve the team's image.
While not mentioned in Use Case 1, AmbulanceService could also be called from the manager Controller when a player gets hit by a dead ball. This also allows us to enjoy the reusability benefits of MVC architecture.
Summary
I summarized abstract MVC concepts and Rails Architecture MVC using diagrams to understand each respectively.
MVC as a software architecture is merely a major concept of role division, and specific implementations differ by framework and project. In the case of Rails MVC, I feel anew that it's convenient to have clear conventions and tool sets prepared from the start.