【发布时间】:2019-01-05 02:36:01
【问题描述】:
我在 Rails 5 项目中的 app/services 文件夹下加载/需要类有多个问题,我开始放弃这个问题。
首先要明确一点,services/ 是我在整个项目中使用的简单 PORO 类,用于从控制器、模型等中抽象出大部分业务逻辑。
这棵树是这样的
app/
services/
my_service/
base.rb
funny_name.rb
my_service.rb
models/
funny_name.rb
失败 #1
首先,当我尝试使用 MyService.const_get('FunnyName') 时,它从我的模型目录中获得了 FunnyName。当我直接执行MyService::FunnyName 时,它似乎没有相同的行为,但在我的大多数测试和更改中,这工作正常,这很奇怪。
我意识到 Rails config.autoload_paths 不会递归加载东西;第一个被捕获的FunnyName 是models/funny_name.rb 是有道理的,因为它肯定已经加载,而不是另一个。
没关系,让我们找到解决方法。我将此添加到我的application.rb:
config.autoload_paths += Dir[Rails.root.join('app', 'services', '**/')]
这会将服务的所有子目录添加到config.autoload_paths。显然,从 Rails 5 开始不建议写这样的东西;但这个想法对我来说确实是正确的。
失败 #2
现在,当我启动我的应用程序时,它会崩溃并输出类似这样的内容
无法自动加载常量 Base,预期 /.../backend/app/services/my_service/base.rb 来定义它(LoadError)
名称已更改,但它是我之前编写的树的匹配路径
问题是,base.rb 是在错误导致我的确切文件中定义的,其中包含类似
class MyService
class Base
end
end
糟糕的解决方案
所以我尝试了其他解决方法,其中很多,但没有任何效果。所以我最终完全删除了 autoload_paths 并将其直接添加到 application.rb
Dir[Rails.root.join('app', 'services', '**', '*.rb')].each { |file| require file }
现在base.rb 已正确加载,MyService.const_get('FunnyName') 实际上将返回正确的类并且一切正常,但这是一个令人作呕的解决方法。此外,它尚未在 production 中进行测试,但它可能会根据环境产生问题。
要求application.rb 提供整棵树听起来是个坏主意,我认为不能这样保留。
在 Rails 中添加自定义 services/ 目录的最简洁方法是什么?它包含多个具有简单名称的子目录和类,这些名称也存在于应用程序的其他部分(模型、base.rb 等)
如何避免混淆 autoload_paths ?还有什么我不知道可以解决问题的方法吗?为什么base.rb 会在这里崩溃?
【问题讨论】:
-
请将您的一个服务定义(第一行应该这样做)添加到您的问题中。
-
你是什么意思?我应该写什么是对我的服务?
-
我的意思是,
app/services/my_class/base.rb是否像class MyClass::Base一样开头? -
写在下面,抱歉我一开始没有高亮显示为代码,所以我不得不编辑它
-
哦,我明白了。这是不正确的。
class MyClass应该是module MyClass。
标签: ruby-on-rails ruby namespaces ruby-on-rails-5