【问题标题】:Rails Presenter - Interacting with 2 different models that share the same attributeRails Presenter - 与共享相同属性的 2 个不同模型交互
【发布时间】:2016-05-31 15:45:53
【问题描述】:

我在大型 Rails 应用程序 roominquiry 中有 2 个模型。他们都共享一个属性/列cancellation_policy

在进行查询(别名:预订)时,cancellation_policyroom.cancellation_policy 复制到inquiry.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.

在各种 RoomController(跨不同的命名空间)中,我可以使用 @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_policy 分开,但这并不能解决RoomInquiry 之间的问题,并且不希望混淆这两个不同的类。


但是,当涉及到将其纳入查询模型和房间模型时,我的主要问题/无知出现了。以下对我来说似乎都非常错误:

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。

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

【问题讨论】:

    标签: ruby-on-rails encapsulation single-responsibility-principle presenter


    【解决方案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
    

    使用stdlib Delegator 作为基类意味着它将丢失的方法委托给被包装的对象。

    例如:

    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(&amp;:present) 获得一个展示的集合。

    module Presentable
      def present
        "#{self.class.name}Presenter".constantize.new(self)
      end
    end
    

    【讨论】:

    • 感谢您提供如此全面的答案。将在接下来的几天内努力实现这一点!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-01-02
    • 1970-01-01
    • 2019-04-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多