Using I18n and Draper to Render Database Attributes

TL;DR;: Check out my additions to ApplicationDecorator in this gist.

When my models have an attribute that matters to the code (like Admin#role or User#status), I like to store the value as a string that makes sense as an identifier. For example, User#status might be ‘active’ or ‘awaiting_approval’. However, when it comes time to render the admin’s role or the users status in the view, we want to show ‘Awaiting approval’ instead of ‘awaiting_approval’. Another example of this sort of thing is the #type attribute for STI.

Ok, this isn’t too hard, we can just use #humanize. But, here’s what happens:

Ok, let’s be fair. All of these solutions are actually quite fine. In most cases Ya Ain’t Gonna Need anything more complicated. The helper version handles most situations just fine.

However, after a bunch of this I tend to end up with a bunch of methods in my model that seem to be somewhat presentation related, and/or methods in my helper that seem like they belong to an object and not in the “global” view namespace.

Enter decorators

A decorator (or presenter) is an object that holds the presentation logic for a model, so that the model can stick to the business logic. I’ve been using a great gem called Draper. I won’t go into too much detail about how to use Draper (check out the Github readme or Railscast).

Here’s how you would implement the above pattern with Draper:

Then this is our view:

Bonus

Now:

My Abstractions

And now the reason for this post. I find that I use this pattern frequently, so I generalized it to ApplicationDecorator. It adds a class method ApplicationDecorator.humanizes that can be used in each decorator to define attributes that need automatic humanization.

The full source can be found here: https://gist.github.com/1338134 (Show inline)

Here’s how you would use it:

And in the view:

To Conclude

I like this because each layer is really simple and really focuses on only what it needs to.

  • The view doesn’t have to know that that data is not user-friendly.
  • The model isn’t polluted with methods designed for the view.
  • There isn’t much complexity or black-magic to make this abstraction simple.

If this pattern works out in my current project I will probably pull this out into a gem. Would anyone else find this useful? If I do I’ll be looking for name suggestions…

Comments
blog comments powered by Disqus