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.

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.

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

Free Training By Email:
Building a Rails Engine

We will send udpates but we care about your data.
No spams.

Back to homepage