Ruby on Rails 3 – 为每个请求重新加载lib目录

我正在为rails 3应用程序创build一个新的引擎。 你可以猜到,这个引擎在我的应用程序的lib目录中。

但是,我有一些问题的发展。 事实上,每当我改变引擎中的东西时,我都需要重新启动服务器。

有没有办法避免这种情况?

我可以强制导轨完全重新加载lib目录或一个特定的文件和他的要求,每个请求?

谢谢你的帮助 :)

TL; DR

  • 把这个在config / application.rb中

    config.eager_load_paths += ["#{Rails.root}/lib"]

  • 删除你的lib文件的require语句

走!


让我详细解释一下。

我不知道为什么这个答案被接受,因为它不能帮助重新加载每个请求的lib文件夹 。 首先,我认为它适用于Rails 2,但问题清楚地表明,这是针对Rails 3,3.0.0的发布date是在答案的date之前。

其他答案似乎过于复杂或不提供真正的解决scheme。

我决定调查一下,因为它困扰了我,我甚至发现人们有一个解决方法,这涉及到在app/models在开发中保存lib文件,然后完成后将其移动到/lib 。 我们可以做得更好,对吧?


我的解决scheme经过testing:

  • Rails 3.0.20
  • Rails 3.1.12
  • Rails 3.2.13
  • Rails 4.0.0.rc1

把这个放到你的config/application.rb

 # in config/application.rb config.eager_load_paths += ["#{Rails.root}/lib}"] 

就是这样!

确保你把它放在这里,因为如果你把它放在config/environments/development.rb ,它将不起作用

确保删除了/lib代码中的所有require语句,因为require语句也会导致此解决scheme无法工作。


这段代码隐含地需要你的代码,所以如果你做环境检查(这是不必要的)而不是上面的代码,你决定写这样的东西:

 # in config/application.rb config.eager_load_paths += ["#{Rails.root}/lib"] if Rails.env.development? 

您应该注意旧的require语句,因为在这种情况下,在所有非开发环境中仍然需要它们。

因此,如果您仍然决定进行环境检查,请确保您对require语句进行反向检查。 否则你会被咬的!

 require "beer_creator" unless Rails.env.development? 

你可能会认为写一整段不必要的东西也是不必要的,但是我认为,在做不需要的事情时,要警告人们有必要的事情也是必要的。

如果您想了解更多关于此主题的信息,请查看这个小教程 。

我不能得到任何上述的工作,所以我挖了一些Rails的代码,并提出这个:

新文件:config / initializers / reload_lib.rb

 if Rails.env == "development" lib_reloader = ActiveSupport::FileUpdateChecker.new(Dir["lib/**/*"]) do Rails.application.reload_routes! # or do something better here end ActionDispatch::Callbacks.to_prepare do lib_reloader.execute_if_updated end end 

是的,我知道这很恶心,但这是一个黑客。 有可能是一个更好的方式来触发一个完整的重新加载,但这对我来说很有用。 我的具体用例是一个Rack应用程序安装到Rails路线,所以我需要它重新加载,因为我在开发中的工作。

基本上它是检查/ lib中的任何文件是否自上次加载后发生更改(修改时间戳),然后在更改时触发重新加载。

我可能还提到我在我的config / application.rb中有这个

 config.autoload_paths += %W(#{config.root}/lib) config.autoload_paths += Dir["#{config.root}/lib/**/"] 

这只是默认情况下,确保我的lib目录中的一切都加载。

Yays!

由于我们正在谈论Rails,所以最简单的方法是使用' require_dependency '来'require'你的lib / * .rb文件。 只要控制器/ helper / etc(app /下的.rb文件)使用require_dependency,而不需要重新加载工作,而不需要做任何事情。

在我走下这条赛道之前,唯一的解决scheme就是在hemju.com上的解决scheme,但是我真的不想为了开发速度而破解ApplicationController。

你必须添加

 config.autoload_paths += %W(#{config.root}/lib) 

到config / application.rb中的Application类

https://rails.lighthouseapp.com/projects/8994/tickets/5218-rails-3-rc-does-not-autoload-from-lib

在RAILS 3中,这里是自动重新加载lib文件的秘密。 下面的代码有点矫枉过正,但是这正是我所做的工作。 您可以更改YoYo#gogo中的消息,并在每次页面加载时在屏幕上看到它。 删除初始化程序,它保持不变。

/config/initializers/lib_reload.rb(新文件)

 ActiveSupport::Dependencies.explicitly_unloadable_constants << 'YoYo' ActiveSupport::Dependencies.autoload_once_paths.delete(File.expand_path(File.dirname(__FILE__))+'/lib') 

/lib/yo_yo.rb

 class YoYo def gogo "OH HAI THERE" end end 

/应用程序/控制器/ home_controller

 require 'yo_yo' class HomeController < ApplicationController def index @message = YoYo.new.gogo end end 

这里是我的版本启发@pbhogan的答案,重新加载您的rails / lib目录中的任何文件被更改时,所有的ruby文件。

它也会使警告消失以避免已经初始化常量的消息。

从Rails 3.2.8开始工作

 if Rails.env.development? lib_ruby_files = Dir.glob(File.join("lib/**", "*.rb")) lib_reloader ||= ActiveSupport::FileUpdateChecker.new(lib_ruby_files) do lib_ruby_files.each do |lib_file| silence_warnings { require_dependency(lib_file) } end end ActionDispatch::Callbacks.to_prepare do lib_reloader.execute_if_updated end end 

更新了答案

我总结了我的博客上的所有发现,你最好看看:

老答案

我四处寻找解决办法,(为了完整起见,也为了指出其他人的方向),我发现了这一点。

从Rails3.1开始,可以通过命令rails plugin new my_plugin --full轻松生成引擎。 这将生成一个引擎的骨架。

--full意味着引擎将被“合并”到包含应用程序中,例如,控制器应该可以直接访问,就好像它们是在包含应用程序中定义的一样。 这可以让你例如在my_engine/app/helpers/my_helper.rb中有一个帮助文件,它将被合并到你的包含应用程序的app/helpers/my_helper.rb helper

还有另外一个选项--mountable ,它为引擎创build一个名称空间,这样它的控制器就不会和包含的应用程序发生冲突。 这会导致例如一个助手在my_engine/app/helpers/my_engine/my_helper.rb ,这将不会与您的包含应用程序中的助手app/helpers/my_helper.rb

现在更有趣的部分

在生成的引擎的test文件夹中,有一个包含完整Rails应用程序的dummy文件夹! 这是为了什么?

当你开发一个引擎时,它的function是完全依靠自己的function完成的,它也应该被完全独立地testing。 因此,在另一个Rails应用程序中“开发”一个引擎是“错误”的方式(尽pipe从Rails应用程序将引擎中的现有function提取到引擎中时,这种方式通常会感觉良好),因此理论上也不需要重新加载引擎代码与包含应用程序的每个请求。

“正确”的方式似乎是这样的:开发和testing你的引擎,就好像它是一个完整的Rails应用程序使用dummy应用程序! 其中,您可以在任何“常规”Rails应用程序中执行您所能做的所有事情,例如创build控制器,模型,视图等,这些应用程序使用引擎应该提供的function。 你也可以在你的test/dummy目录中使用rails s来启动一个服务器,并访问localhost:3000上的虚拟应用程序,当运行你的testing时,这个dummy应用程序将被自动用于集成testing。 相当不错! 🙂

你必须小心把你的东西放在哪里:

  • 任何意图在另一个Rails应用程序中使用的function都将进入my_engine/app ,而任何仅用于testing引擎function的function都将进入test/dummy/app

然后,您可以轻松地将您的引擎加载到主应用程序的Gemfile如下所示: gem 'my_engine', :path => 'path/to/my_engine'或者将它作为gem发布到GitHub。

(一个有趣的事情(回到这个话题的主题)是,当我启动虚拟服务器时,引擎中的所有变化似乎都反映在它内部!所以不知何故似乎可能在Rails中包含一个引擎应用程序没有caching…?我不知道这是怎么发生的。)

总而言之,引擎提供了可以完全独立运行的function,因此也应该自行开发和testing。 然后,当它达到一个稳定的状态时,它可以被其他任何需要它的function的应用程序所包含。

以下是我认为有用的一些资源:

  • 使用Bundler开发RubyGem
  • 可安装引擎RailsCast
  • 本书“Rails 3 in Action”

我希望你觉得这个答案有用。 一般来说,我对引擎还是很陌生的,所以如果有任何错误的信息,请告诉我,我会纠正它。

添加到application_controller.rb或您的基本控制器:

  before_filter :dev_reload if Rails.env.eql? 'development' def dev_reload # add lib files here ["rest_client.rb"].each do |lib_file| ActiveSupport::Dependencies.load_file lib_file end end 

为我工作。

请注意,在Rails 3中,“load_once_paths”变成了“autoload_once_paths”。

此外,它似乎应该是空的,除非你明确地把东西在里面。

另外,请确保在application.rb中注释掉以下行(除了@ dishod的解决scheme),并确保您的模块名称与您的文件名相同(否则,rails将无法find它)

 #Dir.glob("./lib/*.{rb}").each { |file| require file } # require each file from lib directory 

曾经为Rails 3.2.13工作过,在应用程序的gem里面重新加载lib:

require_dependency'the_class'

config.autoload_paths + =%W(#{config.root} /../ fantasy / lib)

    Interesting Posts