我在这里按我认为最重要的顺序列出了它们。
在阅读了几篇文章之后,特别是这篇文章和这篇文章,我开始将控制器中的一些逻辑转移到我的模型中。
但是,即使阅读了更多类似MVC Thought和Model vs. Controller,分离关注点的文章/文章,我也无法决定是否将我的搜索逻辑(在以后的深入解释中)从控制器转移到模型中。还有更多未在此处列出。
看法
两页:
第一页包含一个文本字段和提交按钮,该按钮将POST请求中的用户输入作为参数传递给第二页。
第二页只是在给定数组中渲染每个neatObject,我们称之为@coolList。
控制器
模型
该NeatObject从控制器和回报模型处理请求neatObjects回到那些控制器。
该NeatObject模型定义之间的关系neatObjects在我们的数据库和其他表。
数据库
这些是根据我们的数据库组成每个neatObject的属性:
控制器如何与模型一起使用以获取用户输入的匹配项。
这是我感到困惑的部分。逻辑本身非常简单,但是我不确定哪些部分属于模型,哪些部分属于控制器。
控制器是否应该将搜索字符串传递给模型,然后模型将结果传递回去?
控制器是否应该向模型询问所有的neatObjects,然后仅保留匹配的对象?
解决方案兼有吗?
为了能够询问有关逻辑的特定位的问题,接下来,我将更详细地概述搜索过程。
这一过程涉及发现neatObjects是匹配搜索字符串。如果不定义我们认为的neatObjects匹配项,就不可能继续进行下去。为了使事情变得简单,我们将这样说:
如果搜索字符串包含在其说明或地址中,则neatObject会与搜索字符串匹配,而忽略大小写和前导/结尾空格。
不能保证此定义是永久的。有几件事可能会改变我们的定义。我们可能需要测试更多的属性,而不仅仅是地址和描述,也许是数据库人员添加了一个新的重要属性,或者UI人员决定用户应该能够通过ID进行搜索。当然,与这些情况相反的是,我们需要从正在测试的属性列表中删除一个属性。在许多情况下,可能会改变我们对比赛的定义。我们甚至可能必须添加或删除逻辑,或者如果决定只测试描述属性中的第一个单词,或者如果我们不再忽略大小写的话。
现在我们知道了定义匹配项的内容,并且知道我们的定义可能会更改。现在,我们可以更具体地定义搜索过程。
以下是步骤概述:
在显示可能的实现时,我将参考这些步骤。
搜索功能可以在NeatObject模型或为视图提供服务的控制器中轻松实现。
通常,我只会在控制器中编写所有逻辑,但是在了解了“瘦控制器,胖模型”设计之后,我认为它肯定适用于这种情况。在看到作者在模型中实现了“类似于搜索”功能之后,这篇文章特别让我考虑重新组织代码。作者的功能虽然不能处理用户输入,所以我想知道应该如何处理它。
在学习“ SCFM”之前,这就是我编写代码的方式:
#searches_controller.rb
#This is the method invoked when second page receives POST request
def search
@neatObjects = NeatObjects.all.to_a
@neatObjects.delete_if {
|neatObject| !matches?(neatObject, params[:searchString])
}
end
def matches?(neatObject, searchString)
if((neatObject.description.downcase.include? searchString.downcase) ||
(neatObject.address.downcase.include? searchString.downcase))
return true
end
return false
end
此方法获得其参考的所有的neatObjects通过调用(步骤1) 。所有()在NeatObject模型。它使用数组函数delete_if对每个neatObject进行匹配测试,并仅保留通过测试的对象(第2步)。由于我们将结果存储在服务于视图的控制器中的实例变量中,因此步骤3是自动自动完成的。
将逻辑放置在控制器中非常简单,但是考虑“ SCFM”设计模式时,这似乎非常不合逻辑。
我已经写了另一种选择,其中控制器发送用户输入到模型中的一个功能,它会返回的neatObjects其匹配的输入。
#NeatObject.rb
def self.get_matches_for(searchString)
all.to_a.delete_if { |neighborhood| !matches?(searchString, neighborhood) }
end
def self.matches?(phrase, neighborhood)
fields = [neighborhood.name, neighborhood.address]
fields.map!(&:downcase)
phrase.downcase!
fields.each do |field|
if (
(phrase.include? field) ||
(field.include? phrase)
)
return true
end
end
return false
end
此方法使用all()获取neatObjects的完整列表(步骤1)。与第一种方法一样,模型方法使用delete_if删除不符合特定条件(通过匹配测试)的数组元素(neatObjects)(步骤2)。在此方法中,为视图提供服务的控制器将在NeatObject模型上调用get_matches_for ,并将结果存储在实例变量中(步骤3),如下所示:@neatObjects = NeatObject.get_matches_for( params[:searchString] )
我确实认为该模型选项更干净,并且更易于维护,但是在下一节中,我将进行更深入的介绍。
顾虑
我可以看到模型方法和控制器方法的优缺点,但是我仍然不确定某些事情。
当我阅读了多次引用的文章时(就像我在这里一样),该模型定义了一个函数来返回最近添加的人员是非常合乎逻辑的。
控制器不必执行逻辑来确定是否最近添加了一个人。控制器不应该这样做是有道理的,因为这取决于数据本身。消息的“新近度”测试可能有完全不同的实现。最近的人可能包括本周添加的人,而最近的消息只是今天发送的那些消息。
控制器应该只能够说出People.find_recent
或Message.find_recent
知道它得到了正确的结果。
说find_recent
方法也可以修改为采用时间符号并返回不同时间段的对象是否正确?前-People.find_in_time( :before_this_month )
或Messages.find_in_time( :last_year )
。这是否仍然遵循MVC模式和Rails约定?
控制器是否应该能够找到与用户输入匹配的内容NeatObject.get_matches_for( searchString )
?
我认为匹配逻辑属于模型,因为在测试中使用了某些特定属性,这些属性根据数据而有所不同。对于不同的表,我们可能具有不同的属性,并且控制器绝对不应定义这些属性。我知道控制器取决于模型,而不是模型,因此,即使其余逻辑在控制器中,模型也必须定义那些属性。
上面的文字解释了为什么我认为模型应该处理搜索逻辑并表达我的大部分问题/疑虑,但是我确实有一些赞成其他选择的意见。
如果控制器不处理搜索逻辑,它仍然需要将用户输入发送到模型。它会在发送之前将其清除吗?(删除前导/尾随空格并缩减字符串的大小写。)它是否只是发送从用户那里得到的确切输入?
我最大的一些问题:
如果搜索/匹配过程更简单,代码的位置会改变吗?例如,如果搜索更简单:
如果要测试的唯一属性是地址,并且该地址不太可能更改,那么我们是否将使用控制器来处理搜索?
如果我们要提供高级搜索功能,即用户决定要在搜索中包括哪些属性并控制其他一些因素,那么将有很多用户输入,仅用于定义搜索功能的参数。在模型中放置太多逻辑或用户输入吗?
综上所述
正如许多人在IT和生活中所认为的那样,这取决于规模和目标。
注意事项:
1)对于设计:如果您发现自己多次违反控制器中的DRY,可能是将逻辑移至模型的时候了。
2)为了性能:由于控制器的负载超过了模型的负载,因此控制器中的逻辑性能最差。
同样重要的是:除非您做的事情非常琐碎,并且db有数千行,否则不要使用db进行文本搜索。相反,请使用Solr,ElasticSearch,Sphinx等搜索引擎。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句