Rails 3 Quicktip: Auto reload lib folders in development mode

One of our most popular article is “Rails 3 Quicktip: Autoload lib directory including all subdirectories, avoid lazy loading” in which we describe how autoloading the lib directory in Rails 3 can be done. However, one problem was still there, Rails 3 loads the lib directory on startup, but doesn’t reload the lib directory after that. Hence, if you change a lib file the server has to be restarted (which is quite annoying).

Here is how we can force Rails 3 to reload these files in Development Mode:

First we need to know which files we want to reload. For this purpose we create an initializer that goes through the lib directory and stores the path of all Ruby files:

Could not embed GitHub Gist 822103: API rate limit exceeded for 178.79.134.61. (But here's the good news: Authenticated requests get a higher rate limit. Check out the documentation for more details.)

Now we only need to reload these files on every request. The best place for doing so is the ApplicationController. So we create this before_filter:

Could not embed GitHub Gist 822114: API rate limit exceeded for 178.79.134.61. (But here's the good news: Authenticated requests get a higher rate limit. Check out the documentation for more details.)

The before filter runs only when the constant is defined (in our case in Development Mode) and reloads the file with the changes. No more restarting!

There are a couple of ways to reload the files, but I find this the least hackish way to do it. The downsides of this approach is that we have a before_filter in our ApplicationController that has nothing to do with the application logic and of course reloading all the files on every request slows things down. Nevertheless, not having to restart the server is really really helpful when developing in the lib directory.

See the quicktip in hemju Notes: http://notes.hemju.com/notes/rails-reload-lib-directory

—————

Update 25.4.2011

I updated the ‘reload_lib’ GIST using the suggestions from James’ comment.

12 thoughts on “Rails 3 Quicktip: Auto reload lib folders in development mode

  1. Definitely a good tip and one I could have used the past couple of days while working on my latest project. Thanks.

  2. Why do this:

    before_filter :_reload_libs, :if => :_reload_libs?

    And force two method calls when you can just do this:

    before_filter :_reload_libs

    def _reload_libs
    if defined? RELOAD_LIBS
    RELOAD_LIBS.each do |lib|
    require_dependency lib
    end
    end
    end

    Given that the :if is called on every request anyway (it’s not :if the before_filter should be defined, but whether it should be executed) surely it’s better to have a single method. In terms of the executed code it’s a negligible difference if it’s not defined using my version (a conditional jump in machine code terms) rather than two method calls if it is defined in your version.

    Anyway, just wondering as to your reasoning for doing it this way…

  3. Hi Andy,

    I choose two methods because I think it is more readable (personal preference, I use the underscore at the beginning to indicate some kind of hackish/private stuff). The other reason is that with two methods, I can use _reload_libs? as a helper method and give it out in a debug panel (I have a debug panel in my views in development mode) and _reload_libs? is not necessarily only “defined? RELOAD_LIBS”, it can also have other conditions as well. Further, I like the one-method-does-one-thing coding style because with good method names, its like poetry ;)

    I personally don’t care much about performance when it comes to something like 1 or 2 method calls. Using a framework like Rails (or any other) or a platform like the JVM there are plenty of calls/performance hits/optimizations behind the scene which I don’t know about. Hence, I often don’t know how the application should be optimized. That is why I monitor/measure all my apps (NewRelic is the magic word) and when I spot some performance issues, I will address them.
    For me readable code is more priority then some micro benchmarking.

  4. The enumeration within

    if Rails.env==”development”
    RELOAD_LIBS = []
    Dir["#{Rails.root.to_s}/lib/**/*.rb"].each do |path|
    RELOAD_LIBS << path
    end
    end

    is unnecessary as `Dir.glob` returns an array, `Rails.env` is wrapped in a StringInquirer which means you can use a query method to determine the current environment and `Rails.root` is a `Pathname` which means you have a `:+` method that joins your path in a more readable way.

    The above code could be written more succinctly as

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

  5. Hi James,

    thanks for your suggestions. I discovered Rails.env.development? a couple of weeks ago and haven’t made the changes yet.
    About the Dir.glob and Rails.root, yep, these are definitely good changes and make the code much more readable. Thanks!

  6. Hi, thank you very much for the hint. How about the constants? Have you think about those 
    ugly warnings ‘already initialized constant PIPUZZ”…on every request?  

  7. Not really, the constants are getting reloaded, but it shouldn’t do any harm.

  8. Thank you, for this solution. I just have done this with less code:

      before_filter :reload_libs if Rails.env.development?
     
      private
     
      def reload_libs
        Dir["#{Rails.root}/lib/**/*.rb"].each { |path| require_dependency path }
      end

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>