Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
PoC: Presenters [WIP]
Introduction
Hello, I'm trying to find a better way to handle view logic on Solidus.
Brief recap about view logic management patterns
Helpers have always been the Achilles' heel in the full object oriented world of Rails. Even Steve Klabnik complained about them. So, what are the alternatives?
Presenter pattern
The Presenter pattern couples view logic with the controller / controller and action. So, for example, if you have a
PagesController
withhome
action, you could write:Presentation Model (aka Decorator) pattern
The Decorator pattern couples view logic with the model instance. So, for example, if you have a
User
model, you could write:In this PoC I'm focusing on Decorator pattern, mainly because, looking into Solidus helpers, they seem to me to a greater extent reated to models.
Alternatives
First, I looked into the current state of things regarding existing Ruby presenters implementations. This is the summary:
Draper
API samples
pros
full featured
has been around for a while
pretty popular (~ 4.5k GH stars)
cons
a bit bloated
maintenance is "meh"
Decorator
suffix can't be customized (and we already have decorators concept which would lead to confusion)ActiveDecorator
API samples
pros
from Kaminari's author
simple and clean
Decorator
suffix can be customizedcons
not very popular (~ 200 GH stars)
has auto-decoration. To me it means that we could have many issues like "why is country.name in the controller/view different from self.name in the model class?!"
heavy use of monkey patching
MetaPresenter
pros
Presenter pattern
Uses
Presenter
instead ofDecorator
cons
Presenter pattern
still in early stage
few GH stars (5)
GitLab Presenters
API samples
pros
Simple and effective
Doesn't include all helpers, just URL helpers (URLs are related more to model presentation than to view specific logic)
We can take the best from it and customize to our needs
cons
Proposal
My proposal is based on GitLab Presenters.
API samples
Being this a proof of concept, the implemented API is very simple, its only implemented feature is presentee instance method delegation (see Further features section below for more):
Helper methods / view context
IMHO, we shouldn't include any helpers / view context by default. Presenters are model formatters, they shouldn't know anything about the view format: that's a
render
responsibility. Mixing view format specific logic to presenters leads to spaghetti monsters like this one. I would include only routing and authorization helpers by default. Also, consider thatto_partial_path
provides much flexibility about chosing the right view.If you really need an helper method, you can
include
the helper class you need, or pass the view context from the view as argument to the presenter instance.Performance
Unfortunately, more abstraction comes with runtime overhead cost (ActiveDecorator branch here):
I could verify that performance degradation is mainly due to presenter instances allocation, so it can't be reduced (object oriented programming is the main advantage of presenters). So, performance must be taken in consideration during collection presenters development.
Further features (to be discussed)
Syntactic sugar in order to create presenter instances from object instances. API sample:
IMHO: yes
passing attributes as arguments. API sample:
IMHO: yes
Passing custom presenter to
present
method. Sample API:IMHO: yes. Useful in conjuction with
render
, even more with apresents
helper.present
helper, as syntactic sugar forrender object.present
. API sample:IMHO: yes, I think it's useful to keep things DRY.
Extending helper methods by default. API sample:
IMHO: no.
render adjustment.present as: 'Spree::Adjustment::StateIcon'
could be used instead.Implicit
view_context
method. API sample:IMHO: no. Hard to be properly implemented. Best implementation I've seen (ActiveDecorator) requires Rails monkeypatching. Needed locals can be passed to the presenter as arguments. Needed helpers: see above.