Ruby-on-rails 在 Rails 4 中自动加载 lib 文件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19098663/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Auto-loading lib files in Rails 4
提问by Yarin
I use the following line in an initializer to autoload code in my /libdirectory during development:
/lib在开发过程中,我在初始化程序中使用以下行自动加载目录中的代码:
config/initializers/custom.rb:
配置/初始化程序/custom.rb:
RELOAD_LIBS = Dir[Rails.root + 'lib/**/*.rb'] if Rails.env.development?
(from Rails 3 Quicktip: Auto reload lib folders in development mode)
(来自Rails 3 快速提示:在开发模式下自动重新加载 lib 文件夹)
It works great, but it's too inefficient to use in production- Instead of loading libs on each request, I just want to load them on start up. The same blog has another articledescribing how to do this:
它工作得很好,但在生产中使用效率太低 - 而不是在每个请求上加载库,我只想在启动时加载它们。同一个博客还有另一篇文章描述了如何做到这一点:
config/application.rb:
配置/应用程序.rb:
# Custom directories with classes and modules you want to be autoloadable.
config.autoload_paths += %W(#{config.root}/lib)
config.autoload_paths += Dir["#{config.root}/lib/**/"]
However, when I switch to that, even in development, I get NoMethodErrors when trying to use the lib functions.
但是,当我切换到那个时,即使在开发中,尝试使用 lib 函数时也会出现 NoMethodErrors。
Example of one of my lib files:
我的 lib 文件之一的示例:
lib/extensions.rb:
lib/extensions.rb:
Time.class_eval do
def self.milli_stamp
Time.now.strftime('%Y%m%d%H%M%S%L').to_i
end
end
Calling Time.milli_stampwill throw NoMethodError
调用Time.milli_stamp会抛出 NoMethodError
I realize others have answered similar questions on SO but they all seem to deal with naming conventions and other issues that I didn't to have to worry about before- My lib classes already workedfor per-request loading, I just want to change it to per-startuploading. What's the right way to do this?
我知道其他人的SO回答类似的问题,但他们似乎都应对命名约定和其他问题我没有有大约在─我的lib类已经担心工作的每个请求的负载,我只是想改变它每次启动加载。这样做的正确方法是什么?
回答by ifyouseewendy
I think this may solve your problem:
我认为这可以解决您的问题:
in config/application.rb:
config.autoload_paths << Rails.root.join('lib')and keep the right naming convention in lib.
in lib/foo.rb:
class Foo endin lib/foo/bar.rb:
class Foo::Bar endif you really wanna do some monkey patches in file like lib/extensions.rb, you may manually require it:
in config/initializers/require.rb:
require "#{Rails.root}/lib/extensions"
在config/application.rb 中:
config.autoload_paths << Rails.root.join('lib')并在lib 中保持正确的命名约定。
在lib/foo.rb 中:
class Foo end在lib/foo/bar.rb 中:
class Foo::Bar end如果你真的想在lib/extensions.rb 之类的文件中做一些猴子补丁,你可以手动要求它:
在config/initializers/require.rb 中:
require "#{Rails.root}/lib/extensions"
P.S.
聚苯乙烯
Rails 3 Autoload Modules/Classesby Bill Harding.
And to understand what does Rails exactly do about auto-loading?
read Rails autoloading — how it works, and when it doesn'tby Simon Coffey.
比尔·哈丁 (Bill Harding) 的Rails 3 自动加载模块/类。
并了解 Rails 究竟对自动加载做了什么?
阅读Rails 自动加载——它是如何工作的,以及何时不工作,作者是 Simon Coffey。
回答by lulalala
Though this does not directly answer the question, but I think it is a good alternative to avoid the question altogether.
虽然这并不能直接回答问题,但我认为完全避免这个问题是一个很好的选择。
To avoid all the autoload_pathsor eager_load_pathshassle, create a "lib" or a "misc" directory under "app" directory. Place codes as you would normally do in there, and Rails will load files just like how it will load (and reload) model files.
为了避免所有autoload_paths或eager_load_paths麻烦,在“app”目录下创建一个“lib”或“misc”目录。像往常一样将代码放在那里,Rails 会像加载(和重新加载)模型文件一样加载文件。
回答by sameers
This might help someone like me that finds this answer when searching for solutions to how Rails handles the class loading ... I found that I had to define a modulewhose name matched my filename appropriately, rather than just defining a class:
这可能会帮助像我这样的人在搜索 Rails 如何处理类加载的解决方案时找到这个答案......我发现我必须定义一个module名称与我的文件名匹配的文件,而不仅仅是定义一个类:
In file lib/development_mail_interceptor.rb(Yes, I'm using code from a Railscast :))
在文件lib/development_mail_interceptor.rb 中(是的,我使用的是 Railscast 中的代码 :))
module DevelopmentMailInterceptor
class DevelopmentMailInterceptor
def self.delivering_email(message)
message.subject = "intercepted for: #{message.to} #{message.subject}"
message.to = "[email protected]"
end
end
end
works, but it doesn't load if I hadn't put the class inside a module.
有效,但如果我没有将类放在模块中,它就不会加载。
回答by Madx
Use config.to_prepare to load you monkey patches/extensions for every request in development mode.
使用 config.to_prepare 为开发模式下的每个请求加载猴子补丁/扩展。
config.to_prepare do |action_dispatcher|
# More importantly, will run upon every request in development, but only once (during boot-up) in production and test.
Rails.logger.info "\n--- Loading extensions for #{self.class} "
Dir.glob("#{Rails.root}/lib/extensions/**/*.rb").sort.each do |entry|
Rails.logger.info "Loading extension(s): #{entry}"
require_dependency "#{entry}"
end
Rails.logger.info "--- Loaded extensions for #{self.class}\n"
end
结尾

