只好关了服务重启。
楼上正解。
lz 应该说一下,是如何加载 lib 目录下的文件的。
在 Rails 里有三种加载源码的方式:
require
,这个是 ruby 的方式。Abc::Def
,那么 Rails 就会尝试加载 abc/def.rb
这个文件。文件的搜索路径在 ActiveSupport::Dependencies.autoload_paths
中,可以在 application.rb 中用 config.autoload_paths
中添加。Rails-3 默认没有 'lib' 目录哦。所以默认情况下,使用这种方式加载不了。(load 也算一种,但似乎很少用)
使用第一种方式,应用启动后,只加载一次。使用后两种,在 development 模式下,每次处理新的请求,都会重新加载。
但是要注意,后两种加载的时候,会把源码所在的文件展开为绝对路径,再去 require
。所以,使用 Ruby-1.8.7 的时候要注意了:对于同一个文件,使用不同路径 require
文件,Ruby-1.8.7 会加载多次。所以项目中应该统一使用一种方式加载。
另外:如果想让 ActiveSupport::Dependencies.autoload_paths
中的某个目录的子目录只加载一次,可以添加到 config.autoload_once_paths
中。
饿,还是有问题。大家看看: 首先我在 lib 目录下放置 rb 文件,里面是个 module 模块,命名为 M
其次在 application.rb 中加上 config.autoload_paths += %W(#{config.root}/lib)
最后再 controler 文件中添加,这个时候问题来了 按六楼说,如果是 require,那么只会载入一次,那意味着不能用 require;所以直接写 M.xxx, 结果提示找不到,只好加上 require,正确。但是改 M 的代码,仍然不能即时生效。
#6 楼 @zhangyuan 测试了一下,第二种方法修改 lib 下的文件后扔需重启服务器才能生效,用第三种方法 require_dependency 则可以不重启生效
#15 楼 @lin_style Rails 在找不到常量时,会根据这个常量的名字,加载文件。这确实是 Rails 的惯例。
大致的规则就是,如果类名(常量名、模块名都是常量)是 MaMbMc1::M2::M3
,那么就把 ::
替换为 '/',单词变成小写,并且之间用下划线_
连接,然后尝试在 ActiveSupport::Dependencies.autoload_paths
里的路径中,去查找是否有 ma_mb_mc1/m2/m3.rb
。如果有,那么就会去加载。
我记得 php 可以定义一个方法,在某个类找不到时,去加载某个文件。Rails 和这个大致类似吧。
如果模块名和文件名不一样,那根据上面的规则,肯定是加载不到这个文件的(因为根据模块名得到的文件名是不一致的)。 除非你在代码某个地方使用 require
已经加载了文件。
按照 Rails 的惯例, MaMbMc1::M2::M3
就应该定义在 ma_mb_mc1/m2/m3.rb
文件中。如果在 ma_mb_mc1/m2/m3.rb
中定义的是名为 Mx
的模块,那么第一次使用 MaMbMc1::M2::M3
常量时,就会抛出异常,告诉你 ma_mb_mc1/m2/m3.rb
应该定义 MaMbMc1::M2::M3
。
ActiveSupport::Dependencies.autoload_paths 默认只有 app/assets、app/helpers、app/controllers、app/mailers、app/models 这几个目录。你可以尝试一下,打开终端,输入
ActiveSupport::Dependencies.autoload_paths = []
然后随便输入模型的名字,Rails 都会报错 NameError: uninitialized constant xxx
。因为 Rails 加载模型,也是用 const_missing 机制的。
另外,Rails-2 和 Rails-3 不太一样。Rails-2 没有 ActiveSupport::Dependencies.autoload_paths
,而用了另外一个名字的属性。默认的路径里,不仅包括 lib 在内当前项目里的一些目录,还包括使用到的 gem 里的 lib 目录。