Rails 3 Generators: The Old Faithful

Ben Scofield, Former Viget

Article Category: #Code

Posted on

I figured it would be best to start the tour of Rails 3 generators with those that are most commonly used. Assuming I'm representative of most Rails developers, that would include the following: migrations, models, controllers, and resources. (If your favorite isn't in the list, don't worry! I'll be covering the rest of them soon enough.)

Migration

 [rails2] > ./script/generate migration AddNameToPerson exists db/migrate create db/migrate/20100210021747_add_name_to_person.rb [rails3] > rails generate migration AddNameToPerson invoke active_record create db/migrate/20100210021747_add_name_to_person.rb 

My dad always told me to start simple, and it doesn't get much simpler than the migration generator. In Rails 2.3.5, all it does is check that the migration folder exists and creates the file. In Rails 3, it's almost unchanged. The existence check is now done behind the scenes, and in its place in the output we have a new invoke line.

We'll see invoke a lot as we look at the generators. invoke is a flag that the generator is jumping into a new context, and as you can see here, the output generated while in that new context is indented. In this case specifically, the basic migration generator is handing off control to active_record:migration, which creates the actual migration file. invoke may look trivial, but this is what allows us to swap out generators when we replace components in Rails 3 (for instance, using DataMapper instead of ActiveRecord).

Model

 [rails2] > ./script/generate model Person name:string exists app/models/ exists test/unit/ exists test/fixtures/ create app/models/person.rb create test/unit/person_test.rb create test/fixtures/people.yml exists db/migrate create db/migrate/20100210021556_create_people.rb [rails3] > rails generate model Person name:string invoke active_record create db/migrate/20100210021556_create_people.rb create app/models/person.rb invoke test_unit create test/unit/person_test.rb create test/fixtures/people.yml 

The model generator is only slightly more complicated than the migration generator. Here, you can see that hiding the existence checks cleans up the output a good bit, and you can also see our first example of nested invokes when the basic model generator invokes active_record:model, which in turn invokes test_unit:model.

There are also a number of new options in the model generator:

 TestUnit options: -r, [--fixture-replacement=NAME] # Fixture replacement to be invoked [--fixture] # Indicates when to generate fixture # Default: true ActiveRecord options: [--parent=PARENT] # The parent class for the generated model -t, [--test-framework=NAME] # Test framework to be invoked # Default: test_unit [--migration] # Indicates when to generate migration # Default: true [--timestamps] # Indicates when to generate timestamps # Default: true 

As you might expect, these options come from the TestUnit and ActiveRecord generators, respectively. Finally, we can replace fixtures with something else, or turn 'em off entirely! (Granted, we could already do the latter with --skip-fixture...)

The --parent option is completely new, and makes it easier to generate any STI models you might need – I can only hope this won't become too common, but that's only because of my well-known bias against single-table inheritance.

The --test-framework option is also new, and is another indicator of the flexibility of the Rails 3 generator system.

Controller

 [rails2] > ./script/generate controller People index show exists app/controllers/ exists app/helpers/ create app/views/people exists test/functional/ exists test/unit/helpers/ create app/controllers/people_controller.rb create test/functional/people_controller_test.rb create app/helpers/people_helper.rb create test/unit/helpers/people_helper_test.rb create app/views/people/index.html.erb create app/views/people/show.html.erb [rails3] > rails generate controller People index show create app/controllers/people_controller.rb invoke erb create app/views/people create app/views/people/index.html.erb create app/views/people/show.html.erb invoke test_unit create test/functional/people_controller_test.rb invoke helper create app/helpers/people_helper.rb invoke test_unit create test/unit/helpers/people_helper_test.rb 

With the controller generator, the changes become even more obvious. First, this is the only Rails 3 generator we've seen that doesn't start with invoke. That's because ActionController is a core piece of Rails, and you can't swap it out for an alternative like you can with an ORM or test framework.

After the controller itself is created, the Erb generator is pulled in to create the views. This gives you the freedom to replace Erb (which is technically Erubis in Rails 3) with a different template engine. That's followed by a straightforward invoke of test_unit:controller.

The next new piece is the invocation of the helper generator, which will pop back up in a later post. It's pretty simple, though, creating only a helper file and a unit test (the latter by passing control over to test_unit:helper).

 Options: [--helper] # Indicates when to generate helper # Default: true -t, [--test-framework=NAME] # Test framework to be invoked # Default: test_unit -e, [--template-engine=NAME] # Template engine to be invoked # Default: erb 

New options here include --test-framework and --template-engine, which are self-explanatory, and --helper, which allows you to turn off the helper generator if (like me) you don't like controller-linked helper classes.

Resource

 [rails2] > ./script/generate resource Person name:string exists app/models/ exists app/controllers/ exists app/helpers/ create app/views/people exists test/functional/ exists test/unit/ exists test/unit/helpers/ dependency model exists app/models/ exists test/unit/ exists test/fixtures/ create app/models/person.rb create test/unit/person_test.rb create test/fixtures/people.yml exists db/migrate create db/migrate/20100210021723_create_people.rb create app/controllers/people_controller.rb create test/functional/people_controller_test.rb create app/helpers/people_helper.rb create test/unit/helpers/people_helper_test.rb route map.resources :people [rails3] > rails generate resource Person name:string invoke active_record create db/migrate/20100210021723_create_people.rb create app/models/person.rb invoke test_unit create test/unit/person_test.rb create test/fixtures/people.yml invoke controller create app/controllers/people_controller.rb invoke erb create app/views/people invoke test_unit create test/functional/people_controller_test.rb invoke helper create app/helpers/people_helper.rb invoke test_unit create test/unit/helpers/people_helper_test.rb route resources :people 

Having looked at the model and controller generators, the resource generator should be perfectly understandable. The most interesting thing here is actually in the 2.3.5 output – see that dependency model line? That's what invoke replaced. Who said the old way wasn't modular!

 Options: [--singleton] # Supply to create a singleton controller -c, --resource-controller=NAME # Resource controller to be invoked # Default: controller -o, --orm=NAME # Orm to be invoked # Default: active_record -a, [--actions=ACTION ACTION] # Actions for the resource controller [--force-plural] # Forces the use of a plural ModelName # ... TestUnit options: -r, [--fixture-replacement=NAME] # Fixture replacement to be invoked [--fixture] # Indicates when to generate fixture # Default: true ActiveRecord options: [--parent=PARENT] # The parent class for the generated model [--migration] # Indicates when to generate migration # Default: true [--timestamps] # Indicates when to generate timestamps # Default: true Controller options: [--helper] # Indicates when to generate helper # Default: true -t, [--test-framework=NAME] # Test framework to be invoked # Default: test_unit -e, [--template-engine=NAME] # Template engine to be invoked # Default: erb 

Most of the options here showed up in the model and controller generators, but some are new. The --singleton option, for instance, changes the routing line to represent a singleton resource. I'm not convinced of the utility of the --force-plural option, though, which prevents the generator from singularizing the model name before calling active_record:model.

The other new options here are --actions and --resource-controller. The --actions option allows you to specify a starting set of actions for the controller, which is otherwise bare – and as you might expect, adding actions invokes the appropriate template generator, as well. The --resource-controller lets you override the controller class that is created for your resource. The most obvious use of this would be replacing the basic ApplicationController with a custom class (ResourceController or something similar, for instance), but you can also swap in a Metal controller here, if you like.

Next Up

That does it for the first stop on the tour. Check back soon for the next set of generators, which will include such old standbys as mailer, observer, session_migration, and more!

Related Articles