我在大型Rails应用room
和inquiry
中有2个模型。它们共享一个属性/列cancellation_policy
。
在进行查询(别名:预订)时,cancellation_policy
将从room.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.
在各种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_policy
分开,但这并不能解决Room
和Inquiry
之间的问题以及不希望混淆了两个不同的类。
然而,当涉及到在查询模型和房间模型中加入这个时,我的主要问题/无知。以下一切对我来说都是非常错误的:
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。
如果需要进一步说明,请告诉我。
答案 0 :(得分:0)
首先,我要为演示者创建一个基类,以减少重复量
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(&:present)
获得展示的收藏品。
module Presentable
def present
"#{self.class.name}Presenter".constantize.new(self)
end
end