Me (Andrew Timberlake)

Andrew Timberlake

How to update the Rails scaffold generator to suit your own applications

Rails contains generators that often make your programming a lot easier. One of these is the scaffold generator which creates a base of code that allows you to work with your models immediately. The code that the scaffold generator creates is quite basic and as such I found that very early on I stopped using it alltogether - in fact I don't think I've ever used scaffold code in any project I've done. Now a large number of projects later, I realise that I've been scaffolding my own code by hand for every controller in every action - not very DRY or efficient. Today I decided to roll my sleeves up and put the effort into creating my own scaffold generator. It's really not difficult and will speed up a lot of my development in the future.

The objectives

  • The generated views should use HAML
  • The generated tests should use Shoulda
  • The new and edit view should use the same form partial
  • No layout or css should be generated (I tend to use the main application layout except for special circumstances)

The process

Rails will look for user generators in the ~/.rails/generators/ directory and it will use any generators there before the built-in generators so this is where we will build our custom scaffold generator. First copy the original generator from (if you have the Rails source code) RAILS_SOURCE/railties/lib/rails_generator/generators/components/scaffold/ or (if you have Rails installed as a gem) GEM_SOURCE/rails-x.y.z/lib/rails_generator/generators/components/scaffold In my case it was:
mkdir -p ~/.rails/generators
cp -r ~/dev/rails/railties/lib/rails_generators/generators/components/scaffold ~/.rails/generators/
There are three parts to a generator:
  • The USAGE file - this contains information on how the generator works
  • The <generator_name>_generator.rb file - this is the actual generator code (in our case it's named scaffold_generator.rb)
  • The templates directory - this contains template files that can be used during generation
To use HAML instead of Erb, I editted the template generation at line 56 from "#{action}.html.erb" to "#{action}.html.haml" so now all views are saved with the .haml extension but the views still need to be changed to HAML code.
for action in scaffold_views
m.template(
"view_#{action}.html.erb",
File.join('app/views', controller_class_path, controller_file_name, "#{action}.html.haml")
)
end
While I may be changing the view to HAML code, the template must still be in Erb as the template system will run Erb on the template to allow us to insert code such as class names etc. Here is an example view template after I've made changes:
-title "<%= plural_name %>"
.actions
  =link_to 'New <%= singular_name %>', new_<%= singular_name %>_path
%table{:cellspacing => 0}
  %thead
    %tr
<% for attribute in attributes -%>
      %th <%= attribute.column.human_name %>
<% end -%>
  %tbody
    -@<%= plural_name %>.each do |<%= singular_name %>|
      %tr{:class => cycle(:odd, :even)}
<% for attribute in attributes -%>
        %td= <%= singular_name %>.<%= attribute.name %>
<% end -%>
        %td= link_to 'view', <%= singular_name %>
        %td= link_to 'edit', edit_<%= singular_name %>_path(<%= singular_name %>)
        %td= link_to 'delete', <%= singular_name %>, :confirm => 'Are you sure you want to delete this <%= singular_name %>?', :method => :delete
If you are modifying scaffold views and want to continue to use Erb, you will need to escape all Erb code that should remain in the template with <%% (This is done in the original view templates) The rest of the modification are pretty simple modifications of the scaffold_generator.rb code and the templates. I have put my code on GitHub and you can see a diff of my changes at http://github.com/andrewtimberlake/scripts/commit/095b8615dcff5d37ef94edcc9affed5396fe9731 Some of my modifications depend on the following:
  • Shoulda plugin being installed
  • HAML plugin being installed
  • An application helper method being present called title which allows me to set the page title in a view:
    def title(title_text)
    @title = title_text
    end
To make this really useful, I'm going to be working on a Rails template which is coming in Rails 2.3. I'll write about generating a template in a future post.

Comments

F2cc2eb5f57d402541c6a97b9a0ddb3a?s=50&d=mm
mongo said:
i did something similar -- putting the borrowed generator code in a plugin, but then moving the templates within /lib and symlinking to that directory (so that my templates are really my app's and not the plugins. frankly, i'm not sure why the templates are 'hidden' away so deeply in rails when (if you place them under your control) they really can speed up development time, especially at the beginning -- git://github.com/mongo1515/gaffer_scaff.git your other posts are very useful as well!

Have your say