Create your own helpers for views in rails
Understanding the Issue
The Rails View should be strictly for presentation logic.
Embedding Ruby for domain logic not only blurs the MVC separation but leads to tightly coupled, hard-to-maintain code—often reminiscent of early PHP scripts where HTML, CSS, JavaScript, and server-side code are convoluted.
Keep your HTML clean; any intensive Ruby code in views is likely misplaced.
The Risk of Poor Practices
Inline Ruby in views often scales into maintenance nightmares.
It scatters domain logic, making future refactors or technology shifts cumbersome, slow, and error-prone due to the intricate entanglement of presentation with business logic.
Solution: Extract into Custom Helpers
Refactor Inline Code into Helpers
Using helpers shifts complex Ruby out of ERB templates into testable, tidy Ruby methods, enhancing both clarity and DRY principles.
This makes views cleaner and the associated logic more portable and maintainable.
Example: Improving Link Presentation Logic
Consider the typical scenario in app/views/alerts/index.html.erb
where project-specific links are generated:
<!-- app/views/alerts/index.html.erb -->
<div class="feed">
<% if @project %>
<%= link_to "Subscribe to #{@project.name} alerts.", project_alerts_url(@project, :format => :rss), :class => "feed_link" %>
<% else %>
<%= link_to "Subscribe to these alerts.", alerts_url(format: :rss), :class => "feed_link" %>
<% end %>
</div>
This can be refactored into a helper method to clean up the view:
# app/helpers/alerts_helper.rb
def rss_link(project = nil)
link_to "Subscribe to these #{project&.name} alerts.", alerts_rss_url(project), class: "feed_link"
end
And simplified view:
<!-- app/views/alerts/index.html.erb -->
<div class="feed">
<%= rss_link(@project) %>
</div>
Implementing content_tag
Include elements like <div>
within helpers:
# app/helpers/alerts_helper.rb
def rss_link(project = nil)
content_tag :div, class: "feed" do
link_to "Subscribe to these #{project&.name} alerts", alerts_rss_url(project), class: "feed_link"
end
end
Simplifying with Custom Markup Helpers
Further refactoring with content_tag
replaces link_to
for greater control:
# app/helpers/alerts_helper.rb
def rss_link(project = nil)
content_tag :div, class: "feed" do
content_tag :a, "Subscribe to these #{project&.name} alerts", href: alerts_rss_url(project), class: "feed_link"
end
end
This “greater control” make sens here since we are building our own helper that in the future would be tested.
Organizing Helpers: Avoid ‘application_helper.rb’ Overload
Decouple helpers based on functional contexts within related helper modules to avoid clutter and maintain a logical structure within the application.
Testing Helpers
Leveraging Rails’ Built-ins for Testing
ActionView::TestCase
facilitates robust testing of view helpers.
Example: Testing the rss_link
Helper
Create test cases to ensure correctness:
# test/helpers/alerts_helper_test.rb
require 'test_helper'
class AlertsHelperTest < ActionView::TestCase
test "rss link with project" do
project = Project.create(name: "Test Project")
assert_match /Test Project alerts/, rss_link(project)
assert_match /href=\"#{project_alerts_url(project, format: :rss)}\"/, rss_link(project)
end
test "rss link without project" do
assert_match /Subscribe to these alerts/, rss_link
assert_match /href=\"#{alerts_url(format: :rss)}\"/, rss_link
end
end
Implementing these strategies ensures a clean, maintainable, and efficient view layer in Ruby on Rails applications.
The equation is simple: The less time you spend on coding, the less you pay.
- As a developer: it allows you to switch off and feel confident to get back on it.
- As a manager: you know that your developers are not running in circles by themselves, but are working as a team.
- As a CTO: you make sure that the correlation between the number of lines and time to pay is as least exponential as possible…
Related posts
Building a Rails Engine