人们在 Rails 应用程序中使用 app/services/做什么 [英] What do folks use app/services/ in rails applications

查看:61
本文介绍了人们在 Rails 应用程序中使用 app/services/做什么的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我时不时会在 ruby​​ on rails 生态系统中遇到这种情况:

Every now and them I would come across this in the ruby on rails ecosystem:

class LocalizeUrlService
class Services::UpdateUserRegistrationForOrder
class ProductionOrderEmailService
UserCart::PromotionsService.new(
Shipping::BulkTrackingService.new(bulk_update, current_spree_user)

您还可以在此处查看示例

但是,在例如Ruby On Rails 指南"的官方示例中,我从未见过这一点.这让我相信这是一个来自不同于 Rails/OOP 的另一种语言/范式的概念.

However, in the official examples of for example "Ruby On Rails Guides" I've never seen this. Which leads me to believe this is a concept coming from another language/paradigm different to Rails/OOP.

这种范式/趋势从何而来?有教程/书吗这些人受到了影响吗?这些人是否对几年前的 SOA 趋势持保留态度?

Where is this paradigm/trend coming from? Is there a tutorial/book that these folks got influenced by? Are these folks holdouts from the SOA trend of a few years ago?

将代码放在 app/service/blah_service.rb 是个好主意吗?如果是,什么逻辑/代码可以被认为是服务"材料.是否有任何类型的代码可以/不属于服务?

Is it a good idea to put code in app/service/blah_service.rb ? If yes, what logic/code can be considered "Service" material. Is there any kind code that would/wouldnt belong as a service?

什么 gem/plugin 创建 app/services 文件夹?vanilla rails 应用一开始并没有随附.

What gem/plugin creates the app/services folder? The vanilla rails app doesn't ship with it at first.

sidetone:我个人对实例化服务有疑问.我觉得类和实例化被 ametuer 程序员误用了.我觉得一个类和实例化是为了一件事"而服务是做"的事情所以 mixins/defs/include 应该是我觉得要走的路.

sidetone: Personally I have issue with instantiating a service. I feel classes and instantiating is misused by a ametuer programmers. I feel a class and instantiating is "for a thing" and a service is something that "does" so mixins/defs/include should be the way to go I feel.

推荐答案

服务对象用于不适合正常 MVC 范例的事物.它们通常用于业务逻辑,否则会使您的模型或控制器过于臃肿.通常,它们没有状态(保存在模型中)并且执行诸如与 API 或其他业务逻辑对话之类的事情.服务对象让您的模型保持精简和专注,每个服务对象也很精简,专注于做一件事.

Service objects are for things that don't fit well in the normal MVC paradigm. They're typically for business logic that would otherwise make your models or controllers too fat. Typically they have no state (that's held in a model) and do things like speak to APIs or other business logic. Service objects let you keep your models thin and focused, and each service object is also thin and focused on doing one thing.

Rails 服务对象:综合指南使用服务对象管理与 Twitter 的对话,或封装可能跨多个模型的复杂数据库事务的示例.

Rails Service Objects: A Comprehensive Guide has examples of using service objects to manage talking to Twitter, or encapsulating complex database transactions which might cross multiple models.

Ruby on Rails 中的服务对象……还有你 显示了创建一个服务对象来管理新用户注册过程.

Service Objects in Ruby on Rails…and you shows creating a service object to manage the new user registration process.

EngineYard 博客发布了使用服务保持 RailsControllers Clean and DRY 以处理信用卡的服务对象为例.

The EngineYard blog posted Using Services to Keep Your Rails Controllers Clean and DRY with an example of a service object which does credit card processing.

如果您正在寻找起源,服务对象在Rails 将帮助您设计干净且可维护的代码.这是方法.是从 2014 年他们出现的时候开始的.

If you're looking for the origins, Service objects in Rails will help you design clean and maintainable code. Here's how. is from 2014 when they were coming on the scene.

服务的好处是将应用程序的核心逻辑集中在一个单独的对象中,而不是将其分散在控制器和模型周围.

Services has the benefit of concentrating the core logic of the application in a separate object, instead of scattering it around controllers and models.

所有服务的共同特征是它们的生命周期:

The common characteristic among all services is their lifecycle:

  • 接受输入
  • 执行工作
  • 返回结果

如果这听起来很像函数所做的事情,那你是对的!他们甚至推荐使用 call 作为服务上的公共方法名称,就像 过程.您可以将服务对象视为一种命名和组织大型子程序的方式.

If this sounds an awful lot like what a function does, you're right! They even go so far as to recommend using call as the public method name on the service, just like a Proc. You can think of service objects as a way to name and organize what would otherwise be a big subroutine.

Rails 服务剖析对象 解决了服务对象和关注点之间的区别.它涵盖了服务对象相对于模块的优势.它详细介绍了什么是好的服务对象,包括...

Anatomy of a Rails Service Object addresses the difference between a service object and a concern. It covers the advantages a service object has over modules. It goes into some detail about what makes a good service object including...

  • 不存储状态
  • 使用实例方法,而不是类方法
  • 公共方法应该很少
  • 方法参数应该是值对象,要么被操作要么需要作为输入
  • 方法应该返回富媒体结果对象而不是布尔值
  • 依赖的服务对象应该可以通过私有方法访问,并在构造函数中或延迟创建

例如,如果您有一个应用程序为用户订阅可能是三种模型的列表:用户、列表、订阅.

For example, if you have an application which subscribes users to lists that might be three models: User, List, Subscription.

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

使用基本的createdestroy 方法和关联以及一些回调,在列表中添加和删除用户的过程非常简单.

The process of adding and removing users to and from lists is easy enough with the basic create and destroy methods and associations and maybe a few callbacks.

现在您的老板想要一个精心设计的订阅流程,该流程可以进行大量日志记录、跟踪统计数据、向 Slack 和 Twitter 发送通知、发送电子邮件、进行大量验证……现在什么是简单的createdestroy 变成了一个复杂的工作流程,需要联系 API 并更新多个模型.

Now your boss wants an elaborate subscription process that does extensive logging, tracks statistics, sends notifications to Slack and Twitter, sends emails, does extensive validations... now what was a simple create and destroy becomes a complex workflow contacting APIs and updating multiple models.

您可以将所有这些都编写为关注点或模块,将所有这些内容包含到这三个以前简单的模型中,并编写大的 Subscription.registerSubscription.remove 类方法.现在您的订阅可以发推文并发布到 Slack 并验证电子邮件地址并执行背景调查吗?奇怪的.您的模型现在充斥着与其核心功能无关的代码.

You could write those all as concerns or modules, include all that stuff into these three formerly simple models, and write big Subscription.register and Subscription.remove class methods. Now your subscriptions can Tweet and post to Slack and verify email addresses and perform background checks? Weird. Your models are now bloated with code unrelated to their core functionality.

相反,您可以编写 SubscriptionRegistrationSubscriptionRemove 服务对象.这些可以包括推文和存储统计数据以及执行背景检查等(或者更有可能将其放入更多服务对象)的能力.它们每个都有一个公共方法:SubscriptionRegistration.perform(user, list)SubscriptionRemove.perform(subscription).User、List 和 Subscription 不需要知道任何关于它的信息.你的模特保持苗条,做一件事.每个服务对象只做一件事.

Instead you can write SubscriptionRegistration and SubscriptionRemove service objects. These can include the ability to Tweet and store statistics and perform background checks and so on (or more likely put that into more service objects). They each have one public method: SubscriptionRegistration.perform(user, list) and SubscriptionRemove.perform(subscription). User, List, and Subscription don't need to know anything about it. Your models stay slim and do one thing. And each of your service objects do one thing.

至于您的具体问题...

As to your specific questions...

这种范式/趋势从何而来?

Where is this paradigm/trend coming from?

据我所知,这是胖模型/瘦控制器"趋势的结果;我就是这样来的.虽然这是个好主意,但您的模型通常会变得太胖.即使有模块和关注点,也很难塞进一个单一的类中.通常会使模型或控制器膨胀的其他业务逻辑进入服务对象.

As near as I can tell, it's a consequence of the "fat model / skinny controller" trend; that's how I came to it. While that's a good idea, often your models get TOO fat. Even with modules and concerns, it gets to be too much to cram into a single class. That other business logic which would normally bloat a model or controller goes into service objects.

什么 gem/plugin 创建 app/services 文件夹?

What gem/plugin creates the app/services folder?

你知道.app/ 中的所有内容都会在 Rails 5 中自动加载.

You do. Everything in app/ is autoloaded in Rails 5.

这篇关于人们在 Rails 应用程序中使用 app/services/做什么的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆