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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 22:47:42  来源:igfitidea点击:

Auto-loading lib files in Rails 4

ruby-on-railsruby-on-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:

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

  1. 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
    end
    

    in lib/foo/bar.rb:

    class Foo::Bar
    end
    
  2. if 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" 
    
  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" 
    

P.S.

聚苯乙烯

回答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_pathseager_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

结尾