Home

Dec 08

Automatic Code Reloading in Rails Console

  • rails
  • ruby

Isn’t it nice how Rails server automatically reloads your code before each request in the development? Wouldn’t it be nice if Rails console worked the same way? Sure, you can manually call reload!, but gems like active_reload - or Rails 3.2 itself - make reloading a near no-op most of the time, so we really don’t have to be so stingy about reloading.

Here’s how you can get IRB to reload your code automatically.

Add the following to an initializer (e.g. config/initializers/irb_reloading.rb, or wherever your project’s conventions dictate):

# Disables reloading of observers in railties from
# ActionDispatch::Reloader.to_prepare (in railtie.rb)
module ObserverReloadingDisabler
  module ClassMethods
    def instantiate_observers
      # Don't reload on every irb line executed, thanks
    end
  end

  def self.prepended(base)
    class << base
      prepend ClassMethods unless included_modules.include? ClassMethods
    end
  end
end

module IRBContextWithReloading
  # Overrides the default method to trigger a reload of all files before a line
  # is executed in irb (i.e. script/console)
  def evaluate(line, line_no)
    is_exit_command = %w(quit exit).include?(line.strip)
    unless is_exit_command
      ActiveRecord::Base.send :prepend, ObserverReloadingDisabler
      ActionDispatch::Reloader.prepare!
    end

    result = super(line, line_no)

    unless is_exit_command
      ActionDispatch::Reloader.cleanup!
    end

    result
  end
end

if defined?(IRB::Context) && defined?(Rails::Console) && Rails.env.development?
  IRB::Context.send :prepend, IRBContextWithReloading
  puts '=> IRB code reloading enabled'
end

Now you’re ready to go - your code will be reloaded before IRB evaluates a line, so you can change files and see the changes immediately, without restarting Rails console or calling reload!.


Additional Notes

  • If you are using a version of the ruby-debug gem that overrides IRB::Context#evaluate (version 0.10.4 does, other versions might do so as well), you’ll need to require 'ruby-debug' before the meat of this initializer runs - e.g. as the first line inside the if check.

  • Not using IRB? This idea shouldn’t be difficult to adapt to Pry, or whatever Ruby shell you might be using.


Updated 3/2015

  • The original version used reload!(true), which no longer exists in newer versions of Rails 3. The code now uses ActionDispatch::Reloader instead.

  • Switched to prepend-ing a module instead of re-opening IRB::Context. This should make the code more resilient to patching by other code or gems (i.e. ruby-debug).

  • Added an extra module - ObserverReloadingDisabler - to disable observer reloading. They don’t handle reloading very well. Note that this means changes to observers won’t be reloaded.

 

blog comments powered by Disqus