Ruby on Rails is a framework that delivers a tremendous amount of developer productivity and happiness. Unsurprisingly, Rails application also go through growing pains as they mature. Models and controllers expand until small objects are extracted to keep them under control. The same happens with Rails views; they start out powerful and easy to use and slowly grow out of control. The views become hard to reason about and maintain. Views are also inherently hard to test, so they become the riskiest part of a Rails application.
Decorators are added to contain the situation. Gems exist to help with this, but we don’t need them.
SimpleDelegator is built into Ruby so we can make use of it like so:
Decorators are great, and they help for a while. The problem is that they are tightly coupled to models. Models tend to describe big ideas in the system that are displayed in many different ways. Decorators, therefore, get bloated as they start describing numerous UIs.
Applying basic OOP principles we can break a decorator into smaller objects. Instead of a
CommentDecorator we can build several components:
ReactionButtons, etc. We don’t need a fancy gem to do this. A plain old ruby object will do:
The view component objects can be put under
app/view_components and their templates can be placed in
app/views/components/. The template is just a rails partial that gets a
component local variable.
The view components will each inherit from the main
We’ll add a helper to facilitate the rendering of a view component:
Now anywhere in our views we can render a component with:
View components are ideally minimal as they have a single and focused responsibility. This makes them easy to test and reason about. We can use a real rendering context if we wanted to in tests or mock it and do isolation testing.