在Rails 4中自动加载lib文件

Yar*_*rin 226 ruby-on-rails ruby-on-rails-4

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

配置/初始化/ custom.rb:

RELOAD_LIBS = Dir[Rails.root + 'lib/**/*.rb'] if Rails.env.development?
Run Code Online (Sandbox Code Playgroud)

(来自Rails 3 Quicktip:在开发模式下自动重新加载lib文件夹)

它运行良好,但在生产中使用效率太低 - 而不是在每个请求上加载库,我只想在启动时加载它们.同一篇博客还有另一篇文章描述了如何做到这一点:

配置/ 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/**/"]
Run Code Online (Sandbox Code Playgroud)

但是,当我切换到它时,即使在开发中,我在尝试使用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
Run Code Online (Sandbox Code Playgroud)

调用Time.milli_stamp将抛出NoMethodError

我意识到其他人已经在SO上回答了类似的问题,但他们似乎都在处理命名约定和其他我之前不必担心的问题 - 我的lib类已经为每个请求加载工作了,我只是想改变它到per- 启动加载.这样做的正确方法是什么?

ify*_*ndy 547

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

  1. config/application.rb中:

    config.autoload_paths << Rails.root.join('lib')
    
    Run Code Online (Sandbox Code Playgroud)

    并在lib中保留正确的命名约定.

    lib/foo.rb中:

    class Foo
    end
    
    Run Code Online (Sandbox Code Playgroud)

    lib/foo/bar.rb中:

    class Foo::Bar
    end
    
    Run Code Online (Sandbox Code Playgroud)
  2. 如果你真的想在lib/extensions.rb这样的文件中做一些猴子补丁,你可以手动要求它:

    config/initializers/require.rb中:

    require "#{Rails.root}/lib/extensions" 
    
    Run Code Online (Sandbox Code Playgroud)

PS

  • 这在生产中的Rails 5 API中似乎不起作用(但在开发中).我相信你需要使用`config.eager_load_paths << Rails.root.join('lib')`.然而,这有一个主要的缺点,即'eager_load_paths`也会加载任务中的所有内容.我认为lulalala的解决方案更好.这是一篇博文,内容更详细:http://blog.arkency.com/2014/11/dont-forget-about-eager-load-when-extending-autoload/ (5认同)

lul*_*ala 33

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

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

  • 你错了,Arup,app目录的任何子目录都自动出现在Rails 4.2的autoload_paths数组中.参见http://edgeguides.rubyonrails.org/autoloading_and_reloading_constants.html (6认同)
  • 请记住,`lib`意味着可以应用于多个项目的代码,并且可能被提取到gem.如果没有在app search下创建一个更合适的文件夹作为`services /`或`presenters /`,甚至可以在这些文件中删除它们. (6认同)
  • 我在Rails 4.2中.并且它不会自动加载`app`下的文件,我需要手动执行......或者需要将它放在自动加载路径中.. (3认同)

sam*_*ers 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
Run Code Online (Sandbox Code Playgroud)

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