= Gentlemen, Start your Engines! === Quickstart 1. Install the Rails Engines plugin into your plugins directory 2. Install your engine into the plugins directory (note both of these steps will soon be made somewhat automagic by the new Rails script/plugin command coming in Rails 1.0) 3. Create the RDoc for the engine so you know what's going on: $ cd vendor/plugins/my_engine $ rake rdoc 4. Initialize any database schema provided: $ rake db_schema_import # (still within the plugin/my_engine directory) Beware that this might affect any existing database tables you have installed! You are STRONGLY recommended to inspect the db/schema.rb file to see exactly what running it might change. 5. Add configuration to environment.rb: e.g. # Add your application configuration here module MyEngine config :top_speed, "MegaTurboFast" end Engine.start :my_engine 6. Run your server! $ script/server = Background Rails Engines are a way of dropping in whole chunks of functionality into your existing application without affecting *any* of your existing code. The could also be described as mini-applications, or vertical application slices - top-to-bottom units which provide full MVC coverage for a certain, specific application function. As an example, the Login Engine provides a full user login subsystem, including: * controllers to manage user accounts; * helpers for you to interact with account information from other parts of your application; * the model objects and schemas to create the required tables; * stylesheets and javascript files to enhance the views; * and any other library files required. Once the Rails Core team decides on a suitable method for packaging plugins, Engines can be distributed using the same mechanisms. If you are developing engines yourself for use across multiple projects, linking them as svn externals allows seamless updating of bugfixes across multiple applications. = Building an Engine In your Rails application, you should have a directory called 'engines' in the vendor directory (alongside plugins). This directory will contain one subdirectory for each engine. Here's a sample rails application with a detailed listing of an example engines as a concrete example: RAILS_ROOT |- app |- lib |- config |- <... other directories ...> |- vendor |-plugins |- engines <-- the engines plugin |- some_other_plugin |- my_engine <-- our example engine |- init_engine.rb |- app | |- controllers | |- model | |- helpers | |- views |- db |- tasks |- lib |- public | |- javascripts | |- stylesheets |- test The internal structure of an engine mirrors the familiar core of a Rails application, with most of the engine within the app subdirectory. Within app, the controllers, views and model objects behave just as you might expect if there in teh top-level app directory. When you call Engines.start :my_engine in environment.rb a few important bits of black magic voodoo happen: * the engine's controllers, views and modesl are mixed in to your running Rails application; * files in the lib directory of your engine (and subdirectories) are made available to the rest of your system * any directory structure in the folder public/ within your engine is made available to the webserver * the file init_engine.rb is loaded from within the engine (just like a plugin - the reason why engines need an init_engine.rb rather than an init.rb is because Rails' default plugin system might try and load an engine before the Engines plugin has been loaded, resulting in all manner of badness. Instead, Rails' skips over any engine plugins, and the Engines plugin handles initializing your Engines plugins when you 'start' each engine). From within init_engine.rb you should load any libraries from your lib directory that your engine might need to function. You can also perform any configuration required. === Loading all Engines Calling either Engines.start (with no arguments) or Engines.start_all will load all engines available. Please note that your plugin can only be detected as an engine by the presence of an 'init_engine.rb' file, or if the engine is in a directory named _engine. If neither of these conditions hold, then your engine will not be loaded by Engines.start() or Engines.start_all(). === Configuring Engines Often your engine will require a number of configuration parameters set, some of which should be alterable by the user to reflect their particular needs. For example, a Login System might need a unique Salt value set to encrypt user passwords. This value should be unique to each application. Engines provides a simple mechanism to handle this, and it's already been hinted at above. Within any module, a new method is now available: config. This method creates a special CONFIG Hash object within the Module it is called, and can be used to store your parameters. For a user to set these parameters, they should reopen the module (before the corresponding Engine.start call), as follows: module MyModule config :some_option, "really_important_value" end Engine.start :my_engine Because this config value has been set before the Engine is started, subsequent attempts to set this config value will be ignored and the user-specified value used instead. Of course, there are situations where you *really* want to set the config value, even if it already exists. In such cases the config call can be changed to: config :some_option, "no_THIS_really_important_value", :force The additional parameter will force the new value to be used. For more information, see Module#config. = Tweaking Engines One of the best things about Engines is that if you don't like the default behaviour of any component, you can override it without needing to overhaul the whole engine. This makes adding your customisations to engines almost painless, and allows for upgrading/updating engine code without affecting the specialisations you need for your particular application. === View Tweaks These are the simplest - just drop your customised view (or partial) into you /app/views directory in the corresponding location for the engine, and your view will be used in preference to the engine view. For example, if we have a ItemController with an action 'show', it will (normally) expect to find its view as report/show.rhtml in the views directory. The view is found in the engine at /vendor/engines/my_engine/app/views/report/show.rhtml. However, if you create the file /app/views/report/show.rhtml, that file will be used instead! The same goes for partials. === Controller Tweaks You can override controller behaviour by replacing individual controller methods with your custom behaviour. Lets say that our ItemController's 'show' method isn't up to scratch, but the rest of it behaves just fine. To override the single method, create /app/controllers/item_controller.rb, just as if it were going to be a new controller in a regular Rails application. then, implement your show method as you would like it to happen. ... and that's it. Your custom code will be mixed in to the engine controller, replacing its old method with your custom code. === Model Tweaks Alas, tweaking model objects isn't quite so easy (yet). If you need to change the behaviour of model objects, you'll need to copy the model file from the engine into /app/models and edit the methods yourself. We're working on improving this. = TODO / Future Work * some kind of testing? Integrate with the testing stuff at http://techno-weenie.net/svn/projects/test/ maybe?