Using Helpers instead of Components

According to DHH, components just like default pagination is also a bad idea. Now, it really makes you wonder as to why this stuff makes it into the Rails core in the first place, doesn't it? While the implementation of components is their weak point, the conceptual model behind them is very useful:

Components allow you to call other actions for their rendered response while executing another action. You can either delegate the entire response rendering or you can mix a partial response in with your other content.

Think DRY, a good example is a reusable sidebar which appears on all/many of your pages. In my case, it was the three most recent blog posts which I wanted to show up in the footer of my site. There are several ways of doing this, the most natural of which would be to call on the component, alas apparently it is not an option we should be considering. Another way would be to apply pre-filters to load our collection on every request and then render it in the layout. It works, but it can get tedious, especially if you're trying to add a 'new component' to your code. Instead, let's use a helper! This is how it's going to work, in our application_helper.rb first let's define and retrieve a collection:

  def recent_blog_posts
    posts = Post.find(:all, :limit => 3, :order => 'created_at DESC')
    posts.each { |post| yield(post) }
  end

Code above will retrieve the three latest posts and return them to you one-by-one, now all we need to do is format them in our view (shared/_recent_post.rhtml):

<ul class="dark-menu">
    <% recent_blog_posts do |post| -%>
      <% year = post.created_at.strftime("%Y") -%>
      <% month = post.created_at.strftime("%m") -%>
      <% day = post.created_at.strftime("%d") -%>

      <li><a href="<%= url_for :controller => 'posts', :action => 'show', :id => post, :year => year, :month => month, :day => day %>">
        <span class="date"><%= "#{day}.#{month}"%></span>&nbsp;<%= white_list post.title %></a></li>
    <% end -%>
</ul>

There is a lot of formatting fluff in there, but the idea is simple, the partial calls the helper method, which in turn returns the post objects one by one to it. Now all we need to do is simply call the partial from our template:

<%= render :partial => "shared/recent_posts" %>

This is the cleanest way I found to handle this situation, but I'm open for suggestions.


Ilya Grigorik

Ilya Grigorik is a web performance engineer and developer advocate at Google, where his focus is on making the web fast and driving adoption of performance best practices at Google and beyond.