开发 payslip 时,有一个自定义模块放在 lib/payslip
目录下,在 config/application.rb
目录下添加了config.autoload_paths << Rails.root.join('lib')
,开发环境中跑的好好的,但部署之后,却遇到模块没加载的错误。然后就翻了一下相关文档以及博客。
默认你已经了解自动加载,如果不熟悉的话,请在 Rails 指南中查阅对应文档 Autoloading and Reloading Constants
Eagerload paths
Autoloading 是线程不安全,所以我们要确保 Rails 应用跑起来时所有的常量(Autoloading and Reloading Constants)都加载进来。在使用之前加载所有常量的概念就是 Eagerload ,反之就是 Autoloading
, Autoloading
就是需要使用时才把常量加载。譬如当一个 class 被需要且没有在内存中找到时,Rails 就会在 autoloading paths
路径中查找并加载。
eager_load_paths
包含一些列目录,当 Rails 应用在在生产环境中启动,同时会把列在eager_load_paths
中所列的文件或者文件目录加载。
例如:
# config/application.rb
config.eager_load_paths << Rails.root.join('lib')
Rails 5 生产环境默认不允许 autoloading
就像今天我遇到的错误一下,虽在 config.autoload_paths
中把lib
文件目录添加了,但是在生产环境中仍然找不到需要用的模块。原因就在于此。
通过这个 commit可得知,Rails 应用在生产环境不会执行 autoloading
在生产环境中,Rails 会从 eager_load_paths
中加载所有常量(文件),如果找不到常量,再也不会通过 autoload_paths
继续寻找。
这是比较大的一个改动,如果之前的项目使用了 autoload_paths,升级到 Rails 5 时需要作出对应的改动。譬如之前在 config/application.rb
中如果 config.autoload_paths << Rails.root.join('lib')
,则你需要改为 config.eager_load_paths << Rails.root.join('lib')
另外,在极少数情况下,如果Rails 5 项目很有必要继续沿用 autoloading
,可通过把 enable_dependency_loading
设置为 true
。但是不推荐,我试过通过这样的方式,发现在生产环境中,访问页面,整个性能都慢下来了。
# config/application.rb
config.enable_dependency_loading = true
config.autoload_paths << Rails.root.join('lib')
推荐阅读:
confusing about autoload_paths vs eager_load_paths in rails 4谈到了 autoload-paths 导致页面访问慢的问题。
In production, custom autoload_paths are not respected
网友评论