---
title: It's the little things...
teaser:
tags: web,rails
author: Tammer Saleh
published_on: 2007-07-26
---

Sometimes it's the little things that really make coding fun.

We used to use a common pattern that helped out with our view code.  By adding
the link\_to\_xxx helpers, we could make our applications more consistent and
maintainable:

    def link_to_candidate(candidate, msg = nil)
      link_to(msg || h(candidate.name), candidate_path(candidate))
    end

    def link_to_issue(issue, msg = nil)
      link_to(msg || h(issue.title), issue_path(issue))
    end

    def link_to_intern(intern, msg = nil)
      link_to(msg || h(intern.name), intern_path(intern.candidate, intern))
    end

    #...and on...

But this grows out of hand pretty quickly&#8212;In one application we have over
30 of those puppies. Well, we figured out that by being a little clever, we
could really clean this up...

    def link(item, msg = nil)
      case item
      when Candidate: link_to(msg || h(item.name),  candidate_path(item))
      when Issue:     link_to(msg || h(item.title), issue_path(item))
      when Intern:    link_to(msg || h(item.name),  intern_path(item.candidate, item))
      #...
      else raise ArgumentError, "Unrecognized item given to link: #{item}"
      end
    end

Well, that's much better.  It only grows one line for each model instead of
four, and it's easier to call in the views.

```erb
Candidates!
<% @candidates.each do |candidate| %>
  <%= link candidate %>
<% end %>
```

But it still smells a little fishy.  I don't think anyone here at thoughtbot
likes seeing a case statement. Let's get just a _little_ more clever...

### Abandon hope, all ye who enter here

    def link(item, msg = nil)
      msg ||= item.send([:name, :title, :id].detect {|n| item.respond_to? n})
      method = "#{item.class.name.underscore}_path"
      link_to(msg, self.send(method, item))
    end

If you're still with me&#8212;this version of `link()` figures out what
attribute to call on the give model and generates the xxx_path method.  It's
very concise, and won't grow with the size of your code base, but hot-damn is it
a doozy to decipher.  But a larger issue is that we lost our ability to handle
nested resources (like `intern_path(intern.candidate, intern)`).

Now, we definitely went with the case-statement version up there, but just as an
exercise...

Let's just say we required all nested models to provide a `parents` attribute,
which returned the list of parent models.  We could then clean up our `link()`
method like so:

    def link(item, msg = nil)
      msg ||= item.send([:name, :title, :id].detect {|n| item.respond_to? n})
      method = "#{item.class.name.underscore}_path"
      parents = item.parents rescue []
      link_to(msg, self.send(method, *parents, item))
    end

I wonder what else could be simplified if the models could tell you what other
models proceed them in the resource chain.
