Reloading Your plugin in development mode

For one of my customers I was developing API, wrapped around some older service. This API was meant to be used by new application developed (using RoR of course) by customer itself. Since I was only wrapping old code I could finish quite soon, before main application was ready.

The problem was that API was not defined in every detail upfront. Since I did plain wrapping I did keep old business logic and flow with this API, and new application was not thinking the same way. This was seen before so we have agreed that integration will be done by me and we needed simple way to hook into new application with my integration code. One of obvious ways to achieve it is to use Rails plugin to keep code separated.

Things went OK but I want to share one thing I have learned. Using Rails plugin to wrap code is good idea with one issue – code reloading. Plugin code is not reloaded in development mode (like it is done with controllers or models) so changes in plugin will be visible after application restart. Not very comfortable for development…

Tools for developer
(c) batega

Being lazy and didn’t want to restart application with every change I make, I have started search for some workaround:

In module Dependencies (ActiveSupport::Dependencies in Rails 2.2, Dependencies in main namespace in Rails 2.1 and before) is a little, undocumented attribute explicitly_unloadable_constants, holding array of constants names which will be reloaded with each Rails request. So we just need to add our plugin module name to this array. In config/environments/development.rb add:

ActiveSupport::Dependencies.explicitly_unloadable_constants << 'MyPlugin'

But with plugin You must allow for that. Rails keeps list of paths where reloading is forbidden by default - it is Dependencies.load_paths_once. All plugin directories are on this list. So get rid of this (code for Rails 2.2 - Dependencies scoping):

["my_plugin"].each do |plugin_name|
  reloadable_path = RAILS_ROOT + "/vendor/plugins/#{plugin_name}/lib"
  ActiveSupport::Dependencies.load_once_paths.delete(reloadable_path)
end

Now with each request your plugin will be reloaded (but keep in mind that if you are requiring other files from this plugin, they may not be reloaded - require does keep own list of already loaded paths)

To be honest, this method I have learned from post on Bill Harding's blog, earlier I was just using Dependencies.load_file(and plugin directory removal from load_once_paths) to force reload my plugin:

before_filter :force_plugin_reload
def force_plugin_reload
   ActiveSupport::Dependencies.load_file "my_plugin.rb" if "development" == RAILS_ENV
end

Apparently explicitly_unloadable_constants is much more elegant solution. When do You want to reload something in lib directory You don't have to remove anything from load_once_paths - just add Your module name to .explicitly_unloadable_constants.

Maybe You will find this useful - or do You have other ways how to reload plugins in development mode?

Join the Conversation

9 Comments

  1. n Rails 2.3 you can cause your plugins to be reloaded with each request by adding this to your development.rb file:

    config.reload_plugins = true

    This was possible before, but it required altering Dependencies.load_once_paths and other black magic. I?ve always had issues with these approaches, and so it?s nice to see official support for such a useful feature.

Leave a comment

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.