Rails 悲剧,/lib 目录下的 rb 文件直接修改,不生效?

lin_style · 2012年05月16日 · 最后由 lin_style 回复于 2012年05月21日 · 8233 次阅读

只好关了服务重启。

可以先放到 models 目录,调试好以后在放回 lib 目录

#1 楼 @huacnlee 恩,目前是这样做。。

#1 楼 @huacnlee 我还以为是我在 WINDOWS 下的原因

#1 楼 @huacnlee

不对,貌似也不行。 我文件里面放的是 module 模块。。

楼上正解。

lz 应该说一下,是如何加载 lib 目录下的文件的。

在 Rails 里有三种加载源码的方式:

  1. 使用 require ,这个是 ruby 的方式。
  2. 基于 AcitiveSupport 的 const_missing 机制。如果找不到某个常量(类 或者 模块),就会根据其名称,去加载对应的文件,同时添加到一个已经加载的常量的列表里。比如在代码里使用了 Abc::Def,那么 Rails 就会尝试加载 abc/def.rb 这个文件。文件的搜索路径在 ActiveSupport::Dependencies.autoload_paths 中,可以在 application.rb 中用 config.autoload_paths 中添加。Rails-3 默认没有 'lib' 目录哦。所以默认情况下,使用这种方式加载不了。
  3. 使用 require_dependency 加载。

(load 也算一种,但似乎很少用)

使用第一种方式,应用启动后,只加载一次。使用后两种,在 development 模式下,每次处理新的请求,都会重新加载。

但是要注意,后两种加载的时候,会把源码所在的文件展开为绝对路径,再去 require 。所以,使用 Ruby-1.8.7 的时候要注意了:对于同一个文件,使用不同路径 require文件,Ruby-1.8.7 会加载多次。所以项目中应该统一使用一种方式加载。

另外:如果想让 ActiveSupport::Dependencies.autoload_paths 中的某个目录的子目录只加载一次,可以添加到 config.autoload_once_paths 中。

#6 楼 @zhangyuan LS 讲的相当详细,感谢

#6 楼 @zhangyuan 这种答案没有 reputation 真是可惜了.. 这个系统可以做..

@huacnlee @lgn21st

多谢大家!

饿,还是有问题。大家看看: 首先我在 lib 目录下放置 rb 文件,里面是个 module 模块,命名为 M

其次在 application.rb 中加上 config.autoload_paths += %W(#{config.root}/lib)

最后再 controler 文件中添加,这个时候问题来了 按六楼说,如果是 require,那么只会载入一次,那意味着不能用 require;所以直接写 M.xxx, 结果提示找不到,只好加上 require,正确。但是改 M 的代码,仍然不能即时生效。

@zhangyuan

#10 楼 @lin_style 模块是不是定义在其他模块内?文件名是什么?

如果模块的 全名是 M,那么文件名 就是 m.rb。

我还是习惯把扩展的代码放在 config/initializers 文件夹里下,Rails 启动的时候自动加载,不过如果修改了文件,要重启应用。

#6 楼 @zhangyuan 测试了一下,第二种方法修改 lib 下的文件后扔需重启服务器才能生效,用第三种方法 require_dependency 则可以不重启生效

#13 楼 @reducm 你能确定你要加载的文件,都是用第二种方法加载的吗?能不能给一些代码示例?ActiveSupport::Dependencies.autoload_once_paths 里包括 lib 目录吗?

第二种方式,我已经用了很久了。包括在 Rails-2 和 Rails-3。

#11 楼 @zhangyuan 你好。。模块名和文件名是不一样,这样会影响?我知道 RAILS 有许多习惯的约定

#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 目录。

你 lib 放的东西要符合 rails 自动加载的命名规则,看看源码是怎么放的。

机制是这样,就说明这下面应该放一些不容易被修改或是已经成熟的东西

需要 登录 后方可回复, 如果你还没有账号请 注册新账号