在Rails 4中自动加载lib文件

时间:2013-09-30 15:58:44

标签: ruby-on-rails ruby-on-rails-4

我在初始化程序中使用以下行在开发期间在/lib目录中自动加载代码:

config / initializers / custom.rb:

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

(来自Rails 3 Quicktip: Auto reload lib folders in development mode

它运行良好,但在生产中使用效率太低 - 而不是在每个请求上加载库,我只想在启动时加载它们。同一博客有another article描述如何执行此操作:

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/**/"]

然而,当我切换到那个时,即使在开发中,我在尝试使用lib函数时也会得到NoM​​ethodErrors。

我的一个lib文件示例:

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

调用Time.milli_stamp会抛出NoMethodError

我意识到其他人已经在SO上回答了类似的问题,但他们似乎都在处理命名约定和其他我以前不必担心的问题 - 我的lib类已经工作 for per -request加载,我只想将其更改为per- startup 加载。什么是正确的方法?

4 个答案:

答案 0 :(得分:543)

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

    config / application.rb

    中的
  1. 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" 
    
  3. P.S。

答案 1 :(得分:33)

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

要避免所有autoload_pathseager_load_paths麻烦,请创建一个&#34; lib&#34;或者&#34; misc&#34;目录下&#34; app&#34;目录。像往常一样放置代码,Rails将加载文件,就像加载(和重新加载)模型文件一样。

答案 2 :(得分: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

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

答案 3 :(得分: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"