Show:
Keep the Rails templates and models clean with the Decorator pattern
At the beginning of their career many new Rails developers put complex presentation logic directly into the templates, that looks something like this:
<%= @player.first_name.capitalize + " " + @player.nick_name.capitalize + " " + @player.last_name.capitalize %>
At that point, that kind of solution seems reasonable, but after awhile they all ask the same question: Is this the right place for such a code?
Of course, the answer is always negative, and they rush to find a better place for that code.
By default, Player
model seems like the right place for new clean code, and full_name
method will probably serve the purpose very well. That now looks something like this:
class Player < ApplicationRecord def full_name "#{first_name.capitalize} #{nick_name.capitalize} #{last_name.capitalize}" end end
and in the template we can easily call our new full_name
method:
<%= @player.full_name %>
Great, everything works as expected, and the developer is very proud. This feeling will last as long as developer does not have a lot of similar methods, that can make Player model very huge and difficult to maintain. Which brings us to the Decorator pattern. Lets see how we can use it to keep our Rails templates and models clean.
What is the Decorator pattern?
Decorator pattern enables us to easily add an enhancement to an existing object and to avoid possible problems when we throw all methods in one class (Player model in our case).
So, lets create our decorator. For me, the best practice is to create decorators
directory inside app
directory and to put all of my decorators there. Then we will create PlayerDecorator
class which will inherit from SimpleDelegator
, which is one of native Ruby class from the Ruby Delegator library. Now we can add full_name
method directly to PlayerDecorator
class and remove one from the Player
model.
class PlayerDecorator < SimpleDelegator def full_name "#{first_name.capitalize} #{nick_name.capitalize} #{last_name.capitalize}" end end
We can decorate a Player
model instance before passing it to a template (e.g. form some controller action). Or, we can decorate an Player
model instance directly, within a view, like this:
<%= PlayerDecorator.new(@player).full_name %>
So, to conclude, when you move your complex presentation logic into the decorators, your templates and models will stay clean, and easy to maintain.