我知道之前已经回答了类似的问题 - 例如:
但是我有一个更具体的问题 - 我应该在多大程度上采用这个公理:保持你的控制器瘦,让你的模特变胖!
以下是一个例子:
例如,假设我有多个验证数据来源。一个很好的例子是VIN号码 - 我可以验证它,制造商数据源,DMV的数据源,以及我的本地数据库 - 看看我记录的内容。 所以我有一个名为Vin和vins_controller的模型。在模型中我有5种方法:
在我的控制器中保持REST,在动作节目中 - 我有一个简单的case语句,它查看params [:source],并根据指定的源 - 将调用特定的check方法。
现在问题是: 我应该保留控制在控制器中调用哪个数据源的逻辑,还是应该将其移动到模型中,然后在控制器中执行类似check_vin(source,vin)的操作?
我应该让我的控制器厌食吗?
修改
我将此转换为来自@ jay-godse的官方回答(谢谢 - 当时这是一个很好的答案)。 自2010年以来,情况发生了很大的变化,这个问题仍然得到了一些看法 - 所以希望这会指出一些人正确的方向并帮助他们正确地组织他们的代码。
Trailblazer gem解决了问题中提出的问题。
答案 0 :(得分:19)
有句老话,
智能数据结构和哑码 效果比其他方式好很多 周围。
您所描述的一切都是关于一条数据如何与另一条数据相关。这本身就是你的线索,这些关系的逻辑,包括验证应该在模型或数据库层。
厌食控制器是精心设计(智能?)数据的标志。我的经验告诉我,您在设计数据方面付出的努力越多,整体编写的代码就越少。
控制器最擅长解析输入,调用适当的模型,然后格式化输出。
答案 1 :(得分:4)
我会把逻辑放在我的模型中,特别是如果我是TDD的(我总是TDD,除非我不这样做。)测试模型通常比测试控制器容易得多。
答案 2 :(得分:3)
我喜欢通过思考责任来处理这样的问题。在这种情况下,“负责”验证VIN是什么?该模型。控制器只是根据用户输入传递参数......以“控制”。
如果还不完全清楚的话,可以这样考虑一下:如果需要重新使用此代码会导致影响最小的地方?说...如果两个不同控制器中的两个不同动作都需要验证VIN,那么需要做什么?如果你将这段代码留在控制器中,你基本上也必须在新控制器中复制它,但是如果你把它放在模型中,你只需从新控制器调用check_vin方法,而不是代码需要重复。通过在最有意义的地方分配职责,您已经提高了代码的可重用性。
答案 3 :(得分:2)
控制器有责任“解析”params
,但验证应该在模型中完成。
我会在控制器上做这样的事情:
@my_model = MyModel.new(:source => params[:source] ...)
if(@my_model.valid?)
# treat valid model here (i.e. save the model and redirect to show)
else
# treat validation error here (usually throw an error)
end
你的控制器实际上只是“瘦”。对于真正的“厌食”控制器,您可能需要查看inherited_resources或resource_this。在某些情况下,这些将为您提供一个3行控制器,实现整个RESTful堆栈。
答案 4 :(得分:2)
你应该给Trailblazer一个机会。这是一个基于Rails的瘦框架(实际上,它与所有Ruby框架一起运行),它引入了服务层,表单对象,持久性和域代码之间的间接等等。
将所有软件组件保持为精简是非常有帮助的,因为它为您提供了更多的抽象层,使得更容易找出放置内容的位置。
例如,当你有一个表单对象时,为什么要将验证逻辑按入控制器和模型?