34

I've got a Rails app which uses a gem I'm actively developing. How can I instruct the app to reload the gem on every request?

Jack Kinsella
  • 4,491
  • 3
  • 38
  • 56

5 Answers5

21

This solution almost works but for some reason I have to put it into application.rb and not in environments/development.rb otherwise the autoload_paths are not recognized.

I added some additional stuff which fetches the paths automagically.

if Rails.env.development?
  reload_gems = %w(my_gem other_gem) # names of gems which should autoreload
  config.autoload_paths += Gem.loaded_specs.values.inject([]){ |a,gem| a += gem.load_paths if reload_gems.include? gem.name; a }
  require 'active_support/dependencies'
  ActiveSupport::Dependencies.explicitly_unloadable_constants += reload_gems.map { |gem| gem.classify }
end

Local gems can be added with gem 'my_gem', :path => '../my_gem'

wes
  • 7,795
  • 6
  • 31
  • 41
Kaworu
  • 2,116
  • 1
  • 14
  • 8
  • 1
    This solutions works great, even when added in `environments/development.rb` – fkoessler Jun 15 '15 at 09:33
  • Thank you. It also works great at the bottom of a RSpec rails_helper file, surrounded by "Rails.application.configure do..end". (I'm using Spring, so auto-reloading is needed, as the process lasts for many many test runs) – Matt Hucke May 04 '16 at 18:11
  • Old answer I know but I think this has some problems. It doesn't work with namespaced gems named `namespace-gemname` because `.classify` converts it the wrong name. Also I realize this forces your gem folder structure to match what Rails expects – Andy Ray Feb 13 '19 at 02:23
  • This seems to be something of an unfixable nightmare when dealing with gems with nested namespaces. – Andy Ray Feb 14 '19 at 01:57
6

You could add the path to the gem in the autoload paths for the app.

So, in config/application.rb, within the class Application < Rails::Application ... end block add:

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

Then, when running your development server, all files in there should be reloaded.

Jits
  • 9,647
  • 1
  • 34
  • 27
  • 1
    Thanks but this didn't work for me... could be that the gem is very unconventional - it's a Spree plugin for an engine. I'll come back to the question when I'm developing a more conventional gem. – Jack Kinsella Jun 02 '11 at 09:03
  • 2
    I tried your solution on a more conventional gem within the rails console and it didn't reload the gem following the sending of a reload! message. Perhaps it may work in the app itself. I'll have to wait and see. – Jack Kinsella Jun 22 '11 at 15:00
  • Just the first row and it worked for me. Thx! – benvds Jul 20 '11 at 18:56
2

For an engine:

module Copycat
  class Engine < ::Rails::Engine
    if Rails.env.development?
      config.to_prepare do
        Rails.logger.debug "RELOADING COPYCAT"
        require_dependency Copycat::Engine.root.join('lib', 'copycat').to_s
      end

      config.after_initialize do
        # optional, without it will call `to_prepend` only when a file changes,
        # not on every request
        Rails.application.config.reload_classes_only_on_change = false
      end
    end
  end
end
Kris
  • 19,188
  • 9
  • 91
  • 111
2

I've just found awesome https://github.com/colinyoung/gem_reloader - it works for me!

wojtekk
  • 606
  • 7
  • 7
-4

Super simple fix:

In yourApp/config/envirornments/development.rb:
YourApp::Application.configure do

  # Make sure both of these two settings are set to false, add them if you can't find them
  config.cache_classes =  false
  config.action_controller.perform_caching = false
  #
  #
  # Other config settings...
  #
  #

end