Creating a Rails template generator

Written by Keith McDonnell. Last updated on Tuesday, June 06, 2006.

I use a simple Rails app to publish my articles online. However, each time I
want to create a new article, I must:

  1. Generate a new migration
  2. Create a textile file for the article content
  3. Make sure the article content file name and migration name match

Sounds boring and error prone. Wouldn’t ./script/generate article Rails Rulez be better? Template custom generators to the rescue!

So, we’d like to run ./script/generate article Rails Rulez which:

  1. Generates a new migration named rails_rules.rb
  2. Create a textile file named rails_rules.txtl for the article content

Create the generator directory structure

If you’ll only use the generator in one Rails app, create your custom generator in lib/generators. If you’ll only use the generator in many Rails apps, create your custom generator ~/.rails/generators

Here’s what your directory tree should look like:

|-- USAGE                    (help file)
|-- article_generator.rb     (this file drives ./script/generate article)
`-- templates
*  |-- article.txtl         (the template textile file)
*  `-- publish_article.erb  (the template migration)

Here’s the code which drives the ./script/generate article Foo bar comand

class ArticleGenerator < Rails::Generator::NamedBase
  def manifest 
*  record do |m|
*    # Create artiles directory
*    m.directory ARTICLE_DIR
*    
*    # Create template article
*    m.template "article.txtl", article_file_path
*    
*    # Create article migration
*    m.migration_template "publish_article.rb", "db/migrate", 
*      :migration_file_name => "publish_#{escaped_file_name}"
*  end
  end
end

Obviously, there are some composed methods & a constant missing. The main points to note about the driver file are:

  1. The class name must match the parent directory ArticleGenerator and generator name
  2. The class inherits from Rails::Generator::NamedBase as the generator takes arguments
  3. All the work is done in the record block of the manifest method
  4. If you want to use ERB to generate custom code (insead of a simple copy & paste), use m.template
  5. Use m.migration_template to create a migration from an ERB file
  6. You can pass local variables to your ERB files by passing a hash (see migration_template)
  7. Any methods you define in your custom generator are available in your ERB templates!

A sample migration

class <%= migration_class_name %> < ActiveRecord::Migration
  def self.up
*  Article.create :title => "<%= article_title.humanize %>", 
*    :content => get_article, 
*    :excerpt => ""
  end

  def self.down
*  Article.find_by_title('<%= article_title.humanize %>').destroy rescue nil
  end
end

Where to go from here?

You can use template generators to slash through any repetitive Rails coding. For example, when creating REST controllers you could use a generator to create some or all of the REST actions: ./script/generate rest_controller Rates index show.

If you think your generators might be useful to the wider community, why not release them on rubyforge or github?

See the Rails generator guide for how to test your custom generators.

References

If you'd like to discuss this article, you can send me an email keith@dancingtext.com and/or publish an article online and link back to this page.