在Rails 6之前,有一种简单的方法可以将任何Ruby类拆分为多个文件,而无需引入任何其他模块或关注点。对于那些恰好太大而无法保存在一个文件中的神类,这是非常有用的:
# god.rb
class God < ApplicationRecord
require_dependency 'god~callbacks'
require_dependency 'god~scopes'
require_dependency 'god~search'
require_dependency 'god~something_else'
require_dependency 'god~and_more'
require_dependency 'god~and_even_more'
...
end
# god~callbacks.rb
class God
before_save :nullify_blanks
before_save :nullify_unrelated_attrs
...
end
文件结构如下:
models/
god.rb
god~callbacks.rb
god~scopes.rb
god~search.rb
...
效果很好-随时更改任何这些文件中的任何内容都会正确地重新加载更改。
自Rails 6起,我们使用了新型装载机-Zeitwerk。很棒,但似乎不适用于require_dependency
,至少在以这种非典型方式使用该方法时如此。
问题是,是否可以将类定义拆分为几个文件并保持自动重载与Zeitwerk一起使用。目的是在不引入任何内部模块/问题的情况下拆分类。
而且,请不要评论1000行长的类是否是一种好的设计实践,这不是问题的重点。
答案 0 :(得分:4)
从技术上讲,我相信这是可行的,尽管这种拆分代码的方式并不常见,而且解决方案中的醋比糖还多:)。
首先,您需要告诉Zeitwerk ignore those files。例如,在初始化程序中,您可以执行以下操作:
# ignore accepts a glob pattern.
Rails.autoloaders.main.ignore("god~*")
第二,您需要load
个文件,以便重新加载再次解释它们:
class God < ApplicationRecord
load "#{__dir__}/god~callbacks.rb"
...
end
我假设这些文件未在其他位置加载,所以幂等性并不重要。如果这很重要,那么您需要一些醋。
上面的解决方案未经测试,但是您明白了。
这是拆分代码的一种不寻常的方式,您知道,通常使用模块,模块的名称反映了代码的组织方式,即文件名的作用。我建议使用模块。但是,如果要保留这种样式,原则上可以,尽管解决方案有点强制。
答案 1 :(得分:2)
您可以通过在config.autoload = :classic
文件中设置application.rb
来选择不使用Zeitwerk。如果要继续使用Zeitwerk,为什么不将require_dependency
调用替换为include
?