Using I18n and Draper to Render Database Attributes
Using I18n and Draper to Render Database Attributes
TL;DR: Check out my additions to ApplicationDecorator in this gist.
Update: This has been released as a gem: Olson.
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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
|
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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
Then, in our view:
1 2 3 |
|
1 2 3 4 5 6 |
|
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.
Here’s how you would use it:
1 2 3 4 5 6 7 8 |
|
1 2 3 |
|
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…