OO在Rails中的设计:在哪里放东西
我真的很喜欢Rails(尽管我通常是RESTless),我非常喜欢Ruby。 不过,制作大量ActiveRecord子类和巨大控制器的趋势是非常自然的(即使您对每个资源使用控制器)。 如果你要创建更深层次的对象世界,那么你会在哪里放置类(和模块,我想)? 我在询问有关意见(在助手本身?),控制器和模型。
Lib是好的,我发现了一些解决方案,让它在开发环境中重新加载,但我想知道是否有更好的方法来做这件事。 我真的只关心类太大。 另外,发动机又如何呢?
由于Rails以MVC的方式提供结构,因此最终只使用为您提供的模型,视图和控制器容器是很自然的。 初学者(甚至一些中级程序员)的典型习惯是将应用程序中的所有逻辑嵌入到模型(数据库类),控制器或视图中。
在某些时候,有人指出了“胖模型,瘦控制器”范例,而中间开发人员会急于从控制器中删除所有内容,并将其投入到模型中,从而开始成为应用程序逻辑的新垃圾箱。
实际上,瘦控制器是一个好主意,但推论 - 把所有东西都放在模型中,并不是最好的计划。
在Ruby中,为了使事物更模块化,你有两个很好的选择。 一个相当普遍的答案是只使用包含方法组的模块(通常保存在lib
),然后将模块包含到适当的类中。 这有助于在您希望在多个类中重用功能的类别的情况下,但功能仍按名义附加到类的情况。
请记住,当你将一个模块包含到一个类中时,这些方法将成为该类的实例方法,所以你最终还是会得到一个包含大量方法的类,它们很好地组织在多个文件中。
这种解决方案在某些情况下可以很好地工作 - 在其他情况下,您将需要考虑在代码中使用非模型,视图或控制器中的类。
考虑这个问题的一个好方法是“单一责任原则”,即“单一责任原则”,即一个班级应负责单一(或少数)的事情。 您的模型负责将数据从应用程序持久保存到数据库。 您的控制器负责接收请求并返回可行的响应。
如果您有不完全满足需要的那些箱子(持久性,请求/响应管理)的概念,你可能要想想你将如何有问题的想法建模。 您可以将非模型类存储在app / classes或其他任何地方,并通过执行以下操作将该目录添加到您的加载路径中:
config.load_paths << File.join(Rails.root, "app", "classes")
如果您使用乘客或JRuby,您可能还想将路径添加到热切的加载路径中:
config.eager_load_paths << File.join(Rails.root, "app", "classes")
最重要的是,一旦你在Rails中发现自己提出这个问题的时候,现在是时候加强Ruby的排序,并开始建模,这些类不仅仅是Rails默认给你的MVC类。
更新:这个答案适用于Rails 2.x及更高版本。
更新 :使用关注已被确认为Rails 4中的新默认值。
这真的取决于模块本身的性质。 我通常将控制器/模型扩展放置在应用程序的/ related文件夹中。
# concerns/authentication.rb
module Authentication
...
end
# controllers/application_controller.rb
class ApplicationController
include Authentication
end
# concerns/configurable.rb
module Configurable
...
end
class Model
include Indexable
end
# controllers/foo_controller.rb
class FooController < ApplicationController
include Indexable
end
# controllers/bar_controller.rb
class BarController < ApplicationController
include Indexable
end
/ lib是我的通用库的首选。 我总是在lib中放置一个项目命名空间,我放置了所有应用程序特定的库。
/lib/myapp.rb
module MyApp
VERSION = ...
end
/lib/myapp/CacheKey.rb
/lib/myapp/somecustomlib.rb
Ruby / Rails核心扩展通常发生在配置初始化器中,以便在Rails boostrap上只加载一次库。
/config/initializer/config.rb
/config/initializer/core_ext/string.rb
/config/initializer/core_ext/array.rb
对于可重用的代码片段,我经常创建(微)插件,以便我可以在其他项目中重用它们。
帮助器文件通常包含帮助器方法,有时还包含帮助器(例如Form Builders)使用该对象时的类。
这是一个非常概括的概述。 如果您想获得更多的定制化建议,请提供有关具体示例的更多详细信息。 :)
...制作巨大的ActiveRecord子类和巨大控制器的趋势是很自然的...
“巨大”是一个令人担忧的词... ;-)
你的控制器如何变得巨大? 这是你应该看看的东西:理想情况下,控制器应该很薄。 凭借无与伦比的经验法则,我建议如果您每个控制器方法(操作)的代码经常超过5或6行,那么您的控制器可能太胖了。 是否有可能进入助手功能或过滤器的重复? 是否有业务逻辑可以推入模型?
你的模型如何变得庞大? 你是否应该考虑如何减少每个班级的责任? 有没有可以提取到mixin的常见行为? 或者可以委托给助手类的功能领域?
编辑:试图扩大一点,希望不会扭曲任何太糟糕的...
助手:住在app/helpers
,主要用于简化视图。 它们或者是控制器特定的(也可用于该控制器的所有视图)或通常可用( module ApplicationHelper
中的module ApplicationHelper
)。
过滤器:假设你在几个动作中有相同的代码行(通常,使用params[:id]
或类似的方法检索对象)。 可以首先将这种重复抽象为一个单独的方法,然后完全通过在类定义中声明一个过滤器(如before_filter :get_object
。 请参阅ActionController中的第6部分Rails指南让声明式编程成为您的朋友。
重构模型更像是一件宗教事物。 例如,Bob叔叔的门徒会建议你遵循SOLID的五戒。 乔尔和杰夫可能会推荐更多,呃,“务实”的方法,虽然他们似乎稍后会更加和解。 在一个类中查找一个或多个方法,这些方法对其属性的明确定义的子集进行操作是一种尝试识别可能由ActiveRecord派生模型重构的类的方法。
顺便说一句,Rails模型不一定是ActiveRecord :: Base的子类。 或者换句话说,模型不一定是桌子的模拟,或者甚至与存储的任何东西有关。 更好的是,只要你根据Rails的约定在app/models
命名你的文件(在类名上调用#underscore来找出Rails会寻找什么),Rails会在没有任何require
的情况下找到它。