Rails MVC Violation: Less code in views, more clarity in code
Why Views Should Only Handle Presentation
In the MVC framework, views should only be responsible for presenting data, not preparing it.
When views handle logic and data manipulation, it leads to increased complexity and code duplication.
This complicates testing and violates the single responsibility principle by making the view aware of business logic.
But also add clarity when reading controllers: You can foresee what to expect in the views by reading the controller.
Example of Bad Practice in MVC
Here’s a common pitfall:
Bad View Example
# app/views/users/index.html.erb
<ul>
<% User.order("last_name").each do |user| %>
<li><%= user.full_name %></li>
<% end %>
</ul>
Bad Controller Example
# app/controllers/users_controller.rb
class UsersController < ApplicationController
def index
# No user fetching logic here
end
end
Issues:
- The view directly queries and sorts records (
User.order
), which should be encapsulated in the model. - The controller does not prepare any data for the view, simplifying its duty but at the cost of MVC integrity.
Code Refactoring: MVC Done Right
Revised Model
# app/models/user.rb
class User < ApplicationRecord
scope :ordered_by_last_name, -> { order("last_name") }
end
Revised Controller
# app/controllers/users_controller.rb
class UsersController < ApplicationController
def index
@users = User.ordered_by_last_name
end
end
Revised View
# app/views/users/index.html.erb
<ul>
<% @users.each do |user| %>
<li><%= user.full_name %></li>
<% end %>
</ul>
Improvements:
- The model now encapsulates the logic for ordering users.
- The controller passes the
@users
instance variable prepared for display. - The view focuses solely on rendering, not processing data.
Enhancing Views with Partials and Collections
Take advantage of Rails partials and collections to make your views even cleaner.
Original Approach
# app/views/users/index.html.erb
<%= render partial: "user", collection: @users %>
Partial File
# app/views/users/_user.html.erb
<li><%= user.full_name %></li>
Using Shortcuts:
<%= render @users %>
With this approach, Rails automatically uses the _user.html.erb
partial for each element in @users
. This simplifies the view file, enhances readability, and adheres to DRY principles.
Benefits of Using Partials with Collections:
- Reduced Complexity in Views: Keeps the views clean and focused on presentation.
- Improved Maintainability: Changes to user presentation need only be made in one partial file.
- Enhanced Caching Opportunities: Each partial can be cached individually for performance benefits.
Utilizing partials and collections not only adheres to Rails best practices but also leverages Rails’ powerful rendering engine to manage collections more intuitively. This method keeps your codebase clean, manageable, and performant.
Related posts
Building a Rails Engine