0

我在一个大型 Rails 应用程序中有 2 个模型,room并且inquiry. 他们都共享一个属性/列cancellation_policy

在进行查询(别名:预订)时,从到cancellation_policy复制。room.cancellation_policyinquiry.cancellation_policy


我目前有一个RoomPresenter用这样的对象初始化的room

  def initialize(room, current_user = nil)
    @room = room
    @current_user = current_user
  end

这位演示者会做各种事情来“呈现”一个room. 然而,我最近添加了一堆方法,例如:

 def cancellation_policy_type
 def get_cancellation_policy_text_with_formatting
 etc.

例如,在各种 RoomControllers(跨不同的命名空间)中,我可以实例化@room_presenter = RoomPresenter.new(@room)并调用相关视图中的方法,如预期的那样@room_presenter. def cancellation_policy_type


我觉得我可以采取以下方法

class RoomPresenter
  # gives me access to RoomPresenter#cancellation_policy (see below)
  include RoomPresenters::CancellationPolicy

  def initialize(room)
    @room = room
  end
end

# app/presenters/room_presenters/cancellation_policy.rb
module RoomPresenters
  module CancellationPolicy
    def cancellation_policy
      ###
    end
  end
end

这将以一种合乎逻辑的方式将room演示者方法与room.cancellation_policyRoomInquiry


然而,当涉及到在查询模型和房间模型中结合这一点时,我的主要问题/无知出现了。以下对我来说似乎都非常错误:

class InquiryPresenter (would be initialized with an inquiry).
  include RoomPresenters::CancellationPolicy

同样:

class InquiryPresenter
  #lots of duplicated code doing the same thing/same methods.

我试图了解如何最好地组织这种类型的逻辑,但不确定最好的方法。

底层输出非常简单——每种方法都只是输出一些纯文本或 html,但随着应用程序的进一步发展,我认为需要确保Presenters遵守 SRP。

如果需要进一步解释,请告诉我示例。

4

1 回答 1

1

我将首先为您的演示者创建一个基类以减少重复量

class BasePresenter < Delegator

  def initialize(object)
    @object = object
  end

  # required by Delegator
  def __getobj__
    @object
  end

  def self.model_name
    self.name.chomp("Presenter")
  end

  def self.model_key
    self.model_name.underscore.to_sym
  end

  alias_method :__getobj__, :object

  # declares a getter based on the class name
  # UserPresenter -> #user
  alias_method :__getobj__, self.model_key
end

使用stdlibDelegator作为基类意味着它将把缺少的方法委托给被包装的对象。

例如:

RoomPresenter.new(@room).id == @room.id

我们还创建了一个通用初始化器并@object用于内部存储。内部存储的对象可以通过#object或从类名派生的自定义 getter 访问。

这将让您了解演示者中的样板数量。

class RoomPresenter < BasePresenter
  include RoomPresenters::CancellationPolicy 
end

class InquiryPresenter < BasePresenter
  include RoomPresenters::CancellationPolicy
end

你也可以为你的模型创建一个 mixin 来@room.present代替RoomPresenter.new(@room).

它还可以让你通过做得到一个呈现的集合@rooms.map(&:present)

module Presentable
  def present
    "#{self.class.name}Presenter".constantize.new(self)
  end
end
于 2016-02-19T10:59:16.277 回答