我想将与对象的创建/修改/删除相关的逻辑放在这些对象关联控制器之外的文件中。例如,我想从 User 调用“create_event”方法,但我不想执行“Event.create()”,因为涉及到不属于模型的各种逻辑。这些文件去哪儿了?在库中?这在 Rails 4 中会有什么不同吗?
2009 年提出了同样的问题(在 Ruby on Rails 中将模型“实用程序”功能放在哪里),但由于那是四年前的事,我想确保它仍然是正确的。
我想将与对象的创建/修改/删除相关的逻辑放在这些对象关联控制器之外的文件中。例如,我想从 User 调用“create_event”方法,但我不想执行“Event.create()”,因为涉及到不属于模型的各种逻辑。这些文件去哪儿了?在库中?这在 Rails 4 中会有什么不同吗?
2009 年提出了同样的问题(在 Ruby on Rails 中将模型“实用程序”功能放在哪里),但由于那是四年前的事,我想确保它仍然是正确的。
lib 目录通常用于与您的应用程序无关的逻辑,即您可以在另一个项目中重用。您可以将其视为放置逻辑的目录,该目录应该是一个 gem,但它仍然不是。
正如@meagar 所说,anEventManager
是一种很好的方法,因为此代码将与应用程序逻辑的其余部分一起使用。另一种方法是创建一个EventModule
(in app/modules
),它在处理事件时将包含辅助方法。
lib 绝对不适合那个。正如阿方索所说,它适用于您可以在不同应用程序中重用的类。像一个pdf生成器左右。
Rails 中的模型用于持久性和业务逻辑,但是当这种业务逻辑涉及多个时,它变得更加困难。就我个人而言,我喜欢在控制器和模型之间使用服务层来满足这种需求。
我只是在控制器、模型和视图旁边创建一个文件夹,其中包含诸如 EventService 之类的类。
导轨 4
它不会随 Rails 4 改变
即使这已经快一年了,我还是想重新审视它,以防其他人偶然发现它。经过深思熟虑,我最终制作了位于某些模型和控制器之间的服务类,以处理复杂的表单和关系。这类似于EAA:上面链接的服务层模式,并深受 Ryan Bates 的影响,正如RailsCasts 第 398 集所推荐的那样。在视频中,Ryan 的原话是:“服务对象最适合需要与复杂模型交互的复杂控制器操作,并且没有其他适合该行为的地方”,这完美地描述了我的需求。
当我提出最初的问题时,我很生气,所以它的措辞并不像它本来可以的那样好。我觉得它给人的印象是想要从模型中移除基本行为,但事实并非如此。我会详细说明,以防其他新 Rails 和/或 OOP 的人偶然发现这一点并且知道他们想要完成什么但不知道如何完成。
就我而言,我使用的是 Neo4j,所以对象之间的关系就是对象本身。当处理复杂的关联时(“一个活动有三个乐队和一个场地,可以提交表单,其中包含新的和现有的乐队和场地的任意组合以及需要与乐队/场地对象或关系相关联的唯一数据在他们和事件之间......而且这一切都是通过事件控制器来实现的”)我一直在这些灰色区域中发现自己对任务的责任是有问题的。为特定活动设置独特的乐队描述是活动的工作吗?Rails 会说它是。它会让我将我的参数发送给 Event,然后 Event 会联系到 Band 和 Venue……但为什么那是 Event 的工作?为什么 Event 要与其他对象来回负责这么多?
此外,当某些东西发生故障时,它有时会变成 Where's Waldo 来查找有问题的代码。是事件模型吗?乐队模型?同样,谁拥有连接点的整个过程?他们是共同的责任。归根结底,模型是对象并控制其行为的看门人,但是模型之间共享信息的看门人是什么?
Ryan Bates 在他的网络广播中实现的服务对象是我的救赎。事件控制器将表单数据发送到 EventManager 类。EventManager 将表单拆开,将其中的一部分发送到其他专门的服务类——VenueManager 和 BandManager——它们验证数据,然后在必要时使用它们的关联模型来执行查询和/或创建新对象。辅助服务类向 EventManager 返回对象和布尔响应,然后 EventManager 根据需要设置关系属性。我的行为是孤立的,更容易测试、阅读和扩展。
由于管理类是具有职责的对象,因此我将其包含ActiveModel::Validations
在每一个中。错误会冒出来,我可以放心,如果它遇到麻烦,它会在进程中保释。
任何寻求 Ruby OOP 建议的人都应该阅读Sandi Metz的 Practical Object-Oriented Design in Ruby。对于那些需要改掉一些自学成才的坏习惯,或者只是想考虑更好地组织代码的人来说,阅读和完善它们真的是一种乐趣。基本的 OOP 概念让我清楚地知道,我的管理对象的职责需要与我的 Rails 模型分开处理。