231

I use the following line in an initializer to autoload code in my /lib directory during development:

config/initializers/custom.rb:

RELOAD_LIBS = Dir[Rails.root + 'lib/**/*.rb'] if Rails.env.development?

(from Rails 3 Quicktip: Auto reload lib folders in development mode)

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 article describing how to do this:

config/application.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.

Example of one of my lib files:

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_stamp will throw 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 worked for per-request loading, I just want to change it to per-startup loading. What's the right way to do this?

4

4 回答 4

550

我认为这可能会解决您的问题:

  1. 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
    
  2. 如果你真的想在lib/extensions.rb这样的文件中做一些猴子补丁,你可以手动要求它:

    config/initializers/require.rb 中

    require "#{Rails.root}/lib/extensions" 
    

附言

于 2013-10-29T05:41:39.967 回答
33

虽然这并不能直接回答这个问题,但我认为这是完全避免这个问题的一个很好的选择。

为避免所有麻烦autoload_paths,请eager_load_paths在“app”目录下创建“lib”或“misc”目录。像往常一样放置代码,Rails 会像加载(和重新加载)模型文件一样加载文件。

于 2014-09-25T10:27:34.293 回答
6

这可能会帮助像我这样的人在搜索 Rails 如何处理类加载的解决方案时找到这个答案......我发现我必须定义一个module名称与我的文件名适当匹配的人,而不仅仅是定义一个类:

在文件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 = "myemail@mydomain.org"
    end
  end
end

有效,但如果我没有将类放在模块中,它不会加载。

于 2014-01-24T05:28:05.677 回答
0

使用 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"

结尾

于 2017-07-09T21:29:29.843 回答