I'm discovering the presenter (or decorator) pattern thanks to Ryan Bates' tutorial and implementing it in a training project.
I'm wondering if there's any way to use ActiveSupport delegate
methods between custom objects ?
After refactoring my first model (Product), I'd like to use some ProductPresenter
instance methods inside a CartPresenter
instance. If not, maybe should I use presenter's concerns ?
I'm currently instantiating presenters inside views and accessing helpers methods by redirecting missing methods to the template, but maybe I need to instantiate presenters inside controllers (in order to have access to both CartPresenter
& ProductPresenter
) and define a getter for the template (so it doesn't obfuscate the method_missing
method) ?
EDIT
Thanks to jvillian answer, :product_presenter
now refers to a ProductPresenter instance.
As I may have other situations where I need to delegate presenters methods, I added :delegated_presenter
to my BasePresenter
Class BasePresenter
def initialize(object, template)
@object = object
@template = template
end
def self.delegated_presenter(name)
define_method("#{name}_presenter") do
klass = "#{name.capitalize}Presenter".constantize
@delegator ||= klass.new(@object.send(name), @template)
end
end
end
Now inside my presenter subclasses :
class CartPresenter < BasePresenter
delegated_presenter :product
delegate :product_presenter_instance_method, to: :product_presenter
end
I'm thinking about grouping those into one BasePresenter class method that will do all the job.
This is how it's use inside a view:
<% present product do |product_presenter| %>
<div class="card" style="width: 14rem;">
<%= product_presenter.display_card_image %>
<div class="card-body">
<%= product_presenter.display_link_to_product_name(class: 'card-title text-dark') %>
<%= product_presenter.display_link_to_product_supplier(class: 'small text-right') %>
<%= product_presenter.display_truncated_description(class: 'card-text') %>
<%= render partial: 'product_buttons', locals: { product: product } %>
<%= product_presenter.display_tags(class: 'badge badge-pill badge-secondary') %>
</div>
</div>
<% end %>
present
is a helper method that returns a presenter object.