Tuesday 25 September 2012

Solution: Extract into Custom Helpers

Solution: Extract into Custom Helpers

The most obvious way to deal with excess Ruby code in your views is to remove it. Rails provides the facility to do this by enabling you to move this code into methods called helpers. you can then call the helper methods from the view. Helpers increase readability and maintainability of your views, and because helpers are methods on a Helper class, it's possible to unit test your helper methods, which is typically much easier than doing more complex functional tests in order to test logic that's contained within a view.

For Example, the following is an example of view code in the index view of an AlertsController:

<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>

In this application, AlertsController can either show all alerts across all projects, or it can be limited to show just the alerts of one project. If it's showing alerts for all projects, the text of the link will be "Subscribe to these alerts"; otherwise the link text will include the specific project name.

The view code above can be moved into a helper name rss_link, as shown here:

def rss_link(project = nil)
  if project
   link_to "Subscribe to #{project.name} alerts.",
                  projects_alerts_url(project, :format => :rss), :class => "feed_link"
  else
    link_to "Subscribe to these alerts.", alerts_url(:format => :rss), :class => "feed_link"
  end
end

The rss_link method shown here is essentially the view code moved into a helper method. You can continue to improve this method. There are two reasons you need a conditional in this method:
you need to include the project name in the text of the link, and you need a different URL helper. By creating a second helper method for the determination of the URL helper, you can simplify the rss_link method. You can call this method alerts_rss_url:

def alerts_rss_url(project = nil)
  if project
     project_alerts_url(project, :format => :rss)
  else
    alerts_url(:rss)
  end
end

With this new helper method in place, you can simplify the rss_link method:

def rss_link(project=nil)
  link_to "Subscribe to these #{project.name if project} alerts.", 
                                                       alerts_rss_url(project), :class => "feed_link"
end

You have cleaned up the view by using this method. It's now as simple as the following:

<div class="feed">
  <%= rss_link(@project) %>
</div>

No comments:

Post a Comment