我有一个"小部件",它包含一个html/css代码块。这是一种数据布局,我称之为"堆栈"。
堆栈中嵌入了一些.erb
(RubyonRails),它为每个用户输入数据。
我需要在多个地方包括这个堆栈,它需要表示来自不同模型的不同数据。
因此,一个堆栈可能包含一个名为@company.name
的字段,而另一个堆栈则可能包含@project.name || "Unidentified Project"
。
如何重构/组织这种情况?我可以看到的选项:
- 有两个单独的
stacks
,这将引入冗余和不一致性,但这将是一个明显的问题答案,而不限于特定场景的定制 - 为每个数据点包含
if
语句,以测试堆栈用于何种环境,但对于2个以上的堆栈来说,这是非常糟糕的代码,而且非常复杂 - 一些未知的未知
你将如何解决这个问题?
一个简单的方法是以通用的方式编写erb,使其适用于项目或公司。例如,在您的项目模型中,您可以放置:
def display_name
name || "Unidentified Project"
end
然后在您的公司模型中放入:
def display_name
name
end
当您呈现ERB时,传入一个具有某种通用名称(如main_object
)的变量,并调用其display_name
函数。ERB代码不知道或不关心main_object
是什么类:
<%= main_object.display_name %>
如果在模型中放置与显示相关的函数(如display_name
)会让您感到困扰,则可以使用Presenter模式。礼物基本上是一个普通的旧ruby对象,您可以从模型中创建它,然后将它传递给视图。我看过Jeff Casimir关于这种模式的一篇很好的演讲,名为"胖模特不够用",幻灯片如下:http://en.oreilly.com/rails2011/public/schedule/detail/18514
David的解决方案很好。在某些情况下,您还可以考虑助手或部分(例如,如果您想包含复杂的html)。例如:
助手
def display_name(object)
if object.respond_to? :name and object.name
object.name
else
if object.class.respond_to? :human_name
"Unidentified #{object.class.human_name}"
else
"Unidentified #{object.class.name}"
end
end
end
部分
<%= render :partial => "stack/name/#{object.class.underscore}", :locals => {object.class.underscore => object} %>
app/views/stack/name/_project.html.erb
:中任何复杂ERB
<label style="<%= "background-color: red;" if project.name.blank? %>">
<%= project.name || "Unidentified Project" %>
</label>