Search code examples
ruby-on-rails-3.1

Controlling Rails Initialization for an app extracted as an engine


I was hoping to make a Rails app usable both as an Engine and as a standalone Application.

Specifically, I have a nascent app which I'd like to plug in to a customer's site, but ideally, I'd like to just as easily use the app as a standalone system. However, if config/environments/*.rb exist in the enginified version of my app, I get an Uninitialized Constant error at the time the app that I'm having take a dependency on my engine starts up; Rails complains that the MyEngineModule::Application constant can't be found in development.rb, which I think is simply a load order issue, since this does NOT occur when I run the app standalone. If I delete development.rb, the original initializers that reference my MyEngineModule::Application complain, so then I tried to delete those, and all is well.

Great, except that the original app doesn't work, since its configuration is gone.

Is there some tweak I can make to the initialization load order (or load paths, in the Engine < Rails::Engine class definition) that would prevent the original configs and initializers from being loaded when in an engine context, and allow me to leave them in place for the app context?

The simpler answer is probably this, but I'm feeling stubborn, and would like to know what it would take to make my original goal possible:

  • extract the code for MyEngine into an engine, remove the config/environments/* files and config/initializers/* files, and make the client app depend on this.
  • Make a "new" minimalist app depend on MyEngine, and move the environment files and initializers to NewApp.

Assuming I feel some unnatural compulsion to keep my original application runnable as it was, if I want to prevent the "engine" from loading the "application" configuration, what's the best way to handle that? I presume this is only really a problem during development, because I can prevent the environments/*.rb files from being pulled into the gem itself, but I like being able to test locally while I'm developing the engine and its client app.


Solution

  • Continuing my tradition of answering my own esoteric questions, it seems like one passable alternative is to include a guard clause in the engine's environments/*.rb and the initializers that goes something like this:

    if defined? CuteEngine::Application
      CuteEngine::Application.configure do
        config.whatever = something
      end
    end
    

    This gets around the problem of having two Rails::Application objects at a relatively small cost. Not very happy about it, but I'll live.