ruby-on-rails - 人们在 Rails 应用程序中使用什么 app/services/
问题描述
我现在和他们都会在 ruby on rails 生态系统中遇到这种情况:
class LocalizeUrlService
class Services::UpdateUserRegistrationForOrder
class ProductionOrderEmailService
UserCart::PromotionsService.new(
Shipping::BulkTrackingService.new(bulk_update, current_spree_user)
您还可以在此处查看示例
但是,在例如“Ruby On Rails Guides”的官方示例中,我从未见过这种情况。这让我相信这是一个来自不同于 Rails/OOP 的另一种语言/范式的概念。
这种范式/趋势从何而来?是否有这些人受到影响的教程/书籍?这些人是否对几年前的 SOA 趋势持反对态度?
将代码放在 app/service/blah_service.rb 中是个好主意吗?如果是,哪些逻辑/代码可以被视为“服务”材料。是否有任何类型的代码可以/不属于服务?
什么 gem/plugin 创建了 app/services 文件夹?vanilla rails 应用程序一开始并没有附带它。
sidetone:就我个人而言,我对实例化服务有疑问。我觉得 ametuer 程序员滥用类和实例化。我觉得类和实例化是“为了一件事”,而服务是“做”的事情,所以我觉得 mixins/defs/include 应该是要走的路。
解决方案
服务对象用于不适合正常 MVC 范式的事物。它们通常用于业务逻辑,否则会使您的模型或控制器太胖。通常,它们没有状态(保存在模型中)并执行诸如与 API 或其他业务逻辑对话之类的事情。服务对象让您的模型保持精简和专注,每个服务对象也很精简并专注于做一件事。
Rails Service Objects: A Comprehensive Guide提供了使用服务对象管理与 Twitter 的对话或封装可能跨多个模型的复杂数据库事务的示例。
Ruby on Rails 中的服务对象……您将展示如何创建服务对象来管理新用户注册过程。
EngineYard 博客发布了使用服务保持 Rails 控制器清洁和干燥,并提供了一个服务对象的示例,该服务对象进行信用卡处理。
如果您正在寻找起源,Rails 中的服务对象将帮助您设计干净且可维护的代码。就是这样。是从 2014 年他们来到现场时开始的。
服务的好处是将应用程序的核心逻辑集中在一个单独的对象中,而不是将其分散在控制器和模型周围。
所有服务的共同特征是它们的生命周期:
- 接受输入
- 执行工作
- 返回结果
如果这听起来很像函数的作用,那你是对的!他们甚至建议call
在服务上使用公共方法名称,就像Proc一样。您可以将服务对象视为一种命名和组织大型子例程的方式。
Rails 服务对象剖析解决了服务对象和关注点之间的区别。它涵盖了服务对象相对于模块的优势。它详细介绍了什么是好的服务对象,包括......
- 不存储状态
- 使用实例方法,而不是类方法
- 公共方法应该很少
- 方法参数应该是值对象,可以被操作或者需要作为输入
- 方法应该返回富结果对象而不是布尔值
- 依赖服务对象应该可以通过私有方法访问,并且可以在构造函数中创建或延迟创建
例如,如果您有一个应用程序将用户订阅到可能是三个模型的列表:用户、列表、订阅。
class List
has_many :subscriptions
has_many :users, through: :subscriptions
end
class User
has_many :subscriptions
has_many :lists, through: :subscriptions
end
class Subscription
belongs_to :user
belongs_to :list
end
在列表中添加和删除用户的过程非常简单,使用基本的create
方法destroy
和关联,也许还有一些回调。
现在你的老板想要一个精细的订阅流程,它可以进行大量的日志记录、跟踪统计数据、向 Slack 和 Twitter 发送通知、发送电子邮件、进行大量的验证……现在,从一个简单create
的destroy
流程变成了一个复杂的工作流程,需要联系 API 并更新多个模型。
您可以将所有这些都编写为关注点或模块,将所有这些内容包含在这三个以前简单的模型中,并编写大方法Subscription.register
和Subscription.remove
类方法。现在您的订阅可以在 Slack 上发推文和发帖,并验证电子邮件地址并执行背景调查?诡异的。您的模型现在充斥着与其核心功能无关的代码。
相反,您可以编写SubscriptionRegistration
和SubscriptionRemove
服务对象。这些可以包括推文和存储统计数据以及执行背景检查等的能力(或者更有可能将其放入更多服务对象中)。他们每个人都有一个公共方法:SubscriptionRegistration.perform(user, list)
和SubscriptionRemove.perform(subscription)
. User、List 和 Subscription 不需要知道任何关于它的信息。您的模型保持苗条并做一件事。您的每个服务对象都做一件事。
至于你的具体问题...
这种范式/趋势从何而来?
据我所知,这是“胖模型/瘦控制器”趋势的结果;我就是这样想到的。虽然这是个好主意,但您的模型通常会变得太胖。即使有模块和关注点,塞进一个单一的类也变得太多了。通常会使模型或控制器膨胀的其他业务逻辑进入服务对象。
什么 gem/plugin 创建了 app/services 文件夹?
你做。app/
Rails 5 中的所有内容都是自动加载的。
推荐阅读
- activerecord - Yii 2 getOldAttribute() 方法在 afterSave 中不起作用
- java - 无法将事务 Springboot 提交到 Mysql
- postgresql - 删除重复记录(有效)
- laravel - 在 Laravel 的队列中保持 PHPMailler 连接处于活动状态
- javascript - React Promise.all 挑战
- sqlite - 根据两个表中的通用条件进行查询并根据出现次数进行排序
- python - 报纸(python)获取所有cnn新闻列表
- tfsbuild - TFS 2013:自定义 Git 构建模板错误:找不到自定义模板
- javascript - .Net Core 2 在视图中将 C# 变量转换为 Javascript
- ios - WatchKit - 从 iPhone 访问数据