Rails模型,视图,控制器和助手:什么去了哪里?


155

在Ruby on Rails开发(或通常的MVC)中,关于放置逻辑的位置应该遵循什么快速规则。

请回答是肯定的-有了真的把这个在这里,而不是不把存在

Answers:


173

MVC

控制器:将代码放入此处,该代码与确定用户的需求,确定给他们的内容,确定他们是否已登录,是否应该看到某些数据等有关。最后,控制器会查看请求并计算出要显示的数据(模型)和要呈现的视图。如果您不确定代码是否应放入控制器中,则可能不应该这样做。使您的控制器保持瘦身

视图:视图仅应包含用于显示数据(模型)的最少代码,不应进行大量处理或计算,而应显示由模型计算(或汇总)或由控制器生成的数据。如果您的视图确实需要执行模型或控制器无法完成的处理,则将代码放入帮助器中。视图中的大量Ruby代码使页面标记难以阅读。

模型:模型应该是与数据相关的所有代码(构成您网站的实体,例如,用户,帖子,帐户,朋友等)所在的地方。如果代码需要保存,更新或汇总与您的实体相关的数据,请放在此处。它可以在您的视图和控制器之间重复使用。


2
人们开始摆脱肥胖模型。我喜欢将模型视为数据结构。然后,我编写一些实现该行为的Ruby对象,并使用模型对其进行初始化(它以将模型和模型当作数据的方式一样对待模型,就像将字符串和数组作为Rails外部对象中的数据一样)。这是一个很好的视频,其中包含此技术的示例。
约书亚脸颊

@AdamDonahue我不确定任何东西都可以视为好东西。更好的责任归属于服务。
fatuhoku

35

要补充pauliephonic的答案:

助手:使创建视图更容易的功能。例如,如果您总是要遍历小部件列表以显示其价格,则将其放入帮助器中(连同部分用于实际显示)。或者,如果您有不想使视图混乱的RJS,请将其放入帮助器中。


其实我们也不会在辅助程序中放置sign_in方法吗?正如RoR教程在这里建议的>>> ruby.railstutorial.org/book/…–
Ivan Wang

14

MVC模式实际上仅与UI有关,而与其他无关。您不应该在控制器中放置任何复杂的业务逻辑,因为它控制视图,而不是逻辑。财务主任应考虑选择正确的视图,并将更复杂的内容委派给域模型(模型)或业务层。

域驱动设计具有服务的概念,在这里您需要坚持逻辑,逻辑需要编排许多不同类型的对象,这通常意味着逻辑自然不属于Model类。

我通常将服务层视为应用程序的API。我的服务层通常与我正在创建的应用程序的需求非常接近,因此服务层充当了在我的应用程序较低层中发现的更复杂交互的简化,即,您可以绕过服务层来实现相同的目标但您必须拉更多的杠杆才能使其正常工作。

请注意,我在这里不是在谈论Rails,而是在讨论解决您的特定问题的通用体系结构样式。


这是一个很好的答案:)
卡洛斯·马丁内斯



7

请勿将与授权/访问控制相关的内容放入控制器中。

模型都是关于您的数据的。验证,关系,CRUD,业务逻辑

视图是关于显示数据的。仅显示和获取输入。

控制器是关于控制从模型到视图(和哪个视图)以及从视图到模型的数据。控制器也可以不带模型而存在。

我喜欢将控制器视为安全护卫/接待员,将您(要求)引导您到适当的柜台,您在此询问柜员(查看)问题。然后,出纳员(视图)从从未见过的经理(模型)那里得到答案。您的请求然后返回到保安员/接待员(控制器),等待直到您被指示转到另一个柜员(视图),后者告诉您经理(模型)对另一个柜员(视图)问题的回答。

同样,如果您想告诉出纳员(视图),那么除了第二个出纳员会告诉您经理是否接受您的信息外,基本上会发生相同的事情。由于您无权告诉管理员该信息,因此保安人员/接待员(控制器)也可能已经告诉您进行远足。

因此,为了扩大这个比喻,在我刻板的,不切实际的世界中,出纳员(视图)很漂亮,但是头脑呆滞,并且经常相信您告诉他们的任何内容,安全警卫/接待员虽然礼貌最低,但是知识渊博,但是他们知道人们应该在哪里以及不应该去,经理人确实很丑陋,卑鄙,但知道一切,可以说出什么是真实的,什么不是。


4

有助于正确分离的一件事是避免使用“从控制器传递局部变量到视图”反模式。代替这个:

# app/controllers/foos_controller.rb:
class FoosController < ApplicationController

  def show
    @foo = Foo.find(...)
  end

end

#app/views/foos/show.html.erb:
...
<%= @foo.bar %>
...

尝试将其移至可作为辅助方法使用的吸气剂:

# app/controllers/foos_controller.rb:
class FoosController < ApplicationController

  helper_method :foo

  def show
  end

  protected

  def foo
    @foo ||= Foo.find(...)
  end

end

#app/views/foos/show.html.erb:
...
<%= foo.bar %>
...

这使修改“ @foo”中的内容及其使用方式变得更加容易。它增加了控制器和视图之间的间隔,而不会使其变得更加复杂。


嗯... Yu。能否请您添加一些适当的理由/场景。这打断了KISS和YAGNI的气味,而且非常臭(只是在另一个陈词滥调中折腾了)
Sixty4Bit

2
1)Rails做了很多魔术,将控制器的实例变量复制到您的视图实例中。2)建议的实现也仅在访问foo时加载它,这可能会节省一些时间。重要的答案确实是1)。
webmat

11
叹气这太可怕了。Rails实例变量共享是一项功能,而非反模式。它是一种普遍存在的,低心理开销的语法糖,很少会导致实际问题。如果您不喜欢它,那很好,但是使用巴洛克式非标准结构围绕它进行编码会使事情变得更糟。在这种情况下,您可以有效地使foo成为全局变量(无论如何每个控制器)。试图通过大幅度扩大范围来纠正人们对可变范围的滥用,这具有极大的讽刺意味。
gtd

1
我不购买,dasil003。的范围foo和的@foo是相同的-它们都作用域到<ControllerClass,请求>对。另外,通过使用getter版本,我可以更改Foo查找/存储/缓存该对象的方式,而无需更改视图访问它的方式。
James A. Rosen

1
我认为您的意思是“传递实例变量”反模式。实例var会泄漏整个渲染的状态,即使在深度嵌套的部分中也是如此。您的解决方案还会泄漏状态,但比实例var更好,因为它不允许重新分配。实际上,通过本地方法是最好的方法,因为这就像调用方法一样。局部无法看到局部。看到这个答案
开尔文2013年

2

好吧,这取决于要处理的逻辑...

通常,将更多的内容推入模型中,而使控制器变小是有意义的。这样可以确保可以轻松地在需要访问模型表示的数据的任何位置使用此逻辑。视图应该几乎没有逻辑。因此,总的来说,实际上,您应该努力做到这一点,以免您重复自己。

另外,快速浏览一下Google还会发现一些具体的例子。

模型:验证需求,数据关系,创建方法,更新方法,销毁方法,查找方法(请注意,您不仅应拥有这些方法的通用版本,而且还应做很多事情,例如寻找有红色背景的人头发按姓氏命名,那么您应该提取该逻辑,以便您要做的就是调用find_redH_by_name(“ smith”)或类似的东西)

视图:这应该全部与数据格式有关,而不是数据处理。

控制器:这是数据处理的地方。在互联网上:“控制器的目的是响应用户请求的操作,采用用户设置的任何参数,处理数据,与模型进行交互,然后将请求的数据以最终形式传递给用户。视图。”

希望有帮助。


0

用简单的术语来说,通常, 模型将具有与表相关的所有代码,它们的简单或复杂关系(将它们视为涉及多个表的sql查询),使用业务逻辑对数据/变量进行操作以得出结果。

管制员将拥有针对所要求工作的相关模型的代码/指针。

视图将接受用户输入/交互并显示结果响应。

与这些内容的任何重大偏差都将对该部分造成不必要的负担,并且可能会影响整个应用程序性能。


-1

测试,测试...在模型中放置尽可能多的逻辑,然后就可以正确地对其进行测试。单元测试通过测试模型来测试数据及其形成方式,而功能测试则通过测试控制器来测试路由或控制方式,因此得出结论,除非数据在内部,否则您将无法测试数据的完整性。该模型。

Ĵ

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.