← Home

Oops! Rails already has something better than Engines

To check that out I've reassemled an application that I'm currently working on and that uses Engines to modularize things and added this line to config/environment.rb:


config.plugin_paths << 'vendor/engines'

Now I have a working application with a directory layout like this:


vendor/
  engines/
    adva_blog/
      app/
        controllers/
        helpers/
        models/
        views/
      db/
        migrate/
      init.rb
      routes.rb
    adva_cms/
      ...
    adva_comments/
      ...
    adva_wiki/
      ...
  plugins/
    acts_as_list/
    acts_as_paranoid/
    ...
    will_paginate/

At the same time, the app/ directory is almost empty, because this application is meant as a base or platform for custom applications. Obviously one could move the vendor/engines/ folder somewhere else. Perhaps to apps/ below the app/ directory?.

I totally love this!

But, yeah. Of course this is not exactly the same like what John was talking about. He spoke of first-class sub-apps, i.e. something that's conceptually on the same level as the Rails "app" itself. With Engines those apps are just plugins.

"Just plugins" in Rails 2.0 means that they are actually very powerful. But there are also some traps with unexpected Depenendcies and class reloading issues that plugins in Rails do not live on the same level as the app. They seem to be meant as framework-level extensions, not application-level extensions.

If Rails would at some point compensate for that, probably by inventing the concept of a dedicated "application-level plugin" that behaves exactly the same way as the application itself does (i.e. reloads in dev mode), ... then John's vision finally would have become real.

Until then, though, I'm super happy to be able to store higher-level Engines separate from lower-level plugins :)

Application-level plugins?

The point is that when it comes to, e.g., using ActiveRecord Observers Rails Dependencies produces errors that can be pretty hard to track when models from plugins are involved. There are other several scenarios like this.

My solution to these issues so far is to put the following line into my plugin's init.rb file:


Dependencies.load_once_paths -= Dependencies.load_once_paths.select{|path| \
  path =~ %r(^#{File.dirname(__FILE__)}) }

I haven't understood Dependencies well enough yet though to be sure if that's the best way to do have everything in a plugin be reloaded seemlessly with every request in dev mode. But so far it works quite well.

If you happen to know a better solution please let me know!

Maybe it would be a nice idea to wrap that sucker above into a method on Engines::Plugin. Something like: reloadable! and call that from the init.rb file instead.