Rails 3 Generators: Hooks
Justin Marney, Former Viget
As we saw in some of the earlier posts in the series, the Rails 3 generator API provides a feature that allows you to customize the default generators via plugins or "hooks". For example, you can use a mongomapper generator instead of the default active_record generator in order to generate custom model code. In this installment I'll discuss the hooks that are available in Rails and explain how Rails locates the hooked-in generators as well as show you a great set of existing Rails 3 generator plugins.
Many of the generators in Rails 3 are composed of several smaller generators. For instance, the controller generator has only one action which creates the controller file. It uses hooks to specify that it should also run the view template generator, the controller test generator, and the helper generator. Not only does this keep the generator implementation DRY, each hook also provides a plugin point where you can specify your own generator. Looking at the help output of the controller generator you'll see two of these hook points available via the command line.
Options: -e, [--template-engine=NAME] # Template engine to be invoked # Default: erb -t, [--test-framework=NAME] # Test framework to be invoked # Default: test_unit
After the generator creates the controller file the first thing it will do is run the generator specified by
--template-engine. As it states in the help text the default is
erb. It will search for the
erb generator named
erb:controller which is located in
erb/controller/controller_generator. Note that the generator for creating
erb files within the context of a controller is placed inside the
erb folder. This means that plugins can package up context specific generators and the only requirement to hook up the plugin is to specify the generator package name via the command line.
In addition to specifying generators via command-line hooks you can also set application wide defaults via the application configuration. This is useful as many of the generators use the same hook. For instance, we already saw that the controller generator uses the
template-engine hook to invoke the
erb:controller generator. In addition, the mailer generator will use the same hook to invoke the
erb:mailer generator. If we didn't use an application wide configuration option and wanted to replace our template engine we would need to remember to specify
--template-engine=plugin_name every time we ran the generators.
In order to change the defaults you'll need to include a generator definition block within the application configuration block similar to the following.
config.generators do |g| g.template_engine :haml end
Once this change is made you'll see that the default specified by the generator help text indicates that
haml is the new template engine.
Options: -e, [--template-engine=NAME] # Template engine to be invoked # Default: haml
For reference, here is a list of the hooks used by the Rails 3 generators and their default values.
-c, [--scaffold-controller=NAME] # Scaffold controller to be invoked # Default: scaffold_controller -c, [--resource-controller=NAME] # Resource controller to be invoked # Default: controller -e, [--template-engine=NAME] # Template engine to be invoked # Default: erb [--integration-tool=NAME] # Integration tool to be invoked # Default: test_unit -o, [--orm=NAME] # Orm to be invoked # Default: active_record [--performance-tool=NAME] # Performance tool to be invoked # Default: test_unit -r, [--fixture-replacement=NAME] # Fixture replacement to be invoked # *Default: nil -t, [--test-framework=NAME] # Test framework to be invoked # Default: test_unit
* ActiveRecord model generator provides an action that creates a YAML fixture unless a fixture replacement generator is given.
Fortunately, several people have been hard at work creating a set of Rails 3 generator plugins to handle many of the popular orm, template, and test framework alternatives. Paul Barry has provided a blog post titled Customizing Generators in Rails 3, which details some of the specifics surrounding the package. You can find the repository on indirects's github. This package of generators contains implementations for a host of different hooks including mongomapper, haml, and factory_girl. If your favorite package isn't covered here don't worry. In the next installment of this series we'll cover how to use these hooks to write your own custom generators.