首页 > 解决方案 > 使用 ActiveSupport ``delegate to:'' 来干演示者实例方法

问题描述

多亏了Ryan Bates 的教程,我发现了演示者(或装饰者)模式,并在培训项目中实现了它。

我想知道是否有任何方法可以delegate在自定义对象之间使用 ActiveSupport 方法?在重构我的第一个模型(产品)之后,我想在实例中使用一些ProductPresenter实例方法CartPresenter。如果没有,也许我应该使用演示者的担忧?

我目前正在视图中实例化演示者并通过将缺少的方法重定向到模板来访问辅助方法,但也许我需要在控制器中实例化演示者(以便同时访问CartPresenter& ProductPresenter)并为模板定义一个 getter(所以它不会'不要混淆method_missing方法)?


编辑

感谢 jvillian 的回答,:product_presenter现在指的是 ProductPresenter 实例。

因为我可能有其他需要委托演示者方法的情况,所以我添加:delegated_presenter到我的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

现在在我的演示者子类中:

class CartPresenter < BasePresenter
  delegated_presenter :product
  delegate :product_presenter_instance_method, to: :product_presenter
end

我正在考虑将它们分组到一个 BasePresenter 类方法中,该方法将完成所有工作。

这是它在视图中的使用方式:

<% 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是返回演示者对象的辅助方法。

标签: ruby-on-railsdelegatesdecoratoractivesupportpresenter

解决方案


这个:

delegate :my_instance_method, to: :product_presenter

...不起作用,因为:product_presenter它是symbol,而不是ProductPresenter. 也许尝试更多类似的东西:

class CartPresenter

  delegate :my_instance_method, to: product_presenter 

  def product_presenter
    @product_presenter ||= ProductPresenter.new 
  end

end

...和...

class ProductPresenter

  def my_instance_method
    # do something
  end

end

这个说法:

我目前正在视图中实例化演示者

...我有点担心,因为您正在视图和演示者之间创建紧密耦合。这是一个较长的主题,但如果我生成您在代码中显示的视图,它看起来更像:

<% @presenter = local_assigns[:presenter] if local_assigns[:presenter] %>

<div class="card" style="width: 14rem;">
  <%= @presenter.card_content %>
</div>

然后,很自然地,你传入的任何 Presenter 都locals需要实现card_content. 现在,您的视图对除该一种方法之外的其他方法一无所知, . 您可以做任何您想做的事情,并在将来对方法进行更改,而不必担心更新您的视图。解耦!presentercard_contentcard_contentproduct_presenter


推荐阅读