16.2. Templates

Once you have been working with Rails for a while, you will always make the same changes after calling rails generate scaffold or rails generate model. You are going to adapt the scaffold to your requirements. Fortunately, you can replace the Rails templates for creating the controller or model files with your own custom templates. This saves a lot of time.
I am going to show you the basic principle by using the controller and model template as an example.

Tip

15 minutes spent optimizing a template in accordance with your requirements will save you many hours of work later in every Rails project!

Scaffold Controller Template

Let's assume you want to create a scaffold User:
$ rails generate scaffold User first_name last_name login
      [...]
      invoke  scaffold_controller
      create    app/controllers/users_controller.rb
      [...]
$
The controller app/controllers/users_controller.rb generated by default then looks like this in Rails 3.2:
class UsersController < ApplicationController
  # GET /users
  # GET /users.json
  def index
    @users = User.all

    respond_to do |format|
      format.html # index.html.erb
      format.json { render json: @users }
    end
  end

  # GET /users/1
  # GET /users/1.json
  def show
    @user = User.find(params[:id])

    respond_to do |format|
      format.html # show.html.erb
      format.json { render json: @user }
    end
  end

  # GET /users/new
  # GET /users/new.json
  def new
    @user = User.new

    respond_to do |format|
      format.html # new.html.erb
      format.json { render json: @user }
    end
  end

  # GET /users/1/edit
  def edit
    @user = User.find(params[:id])
  end

  # POST /users
  # POST /users.json
  def create
    @user = User.new(params[:user])

    respond_to do |format|
      if @user.save
        format.html { redirect_to @user, notice: 'User was successfully created.' }
        format.json { render json: @user, status: :created, location: @user }
      else
        format.html { render action: "new" }
        format.json { render json: @user.errors, status: :unprocessable_entity }
      end
    end
  end

  # PUT /users/1
  # PUT /users/1.json
  def update
    @user = User.find(params[:id])

    respond_to do |format|
      if @user.update_attributes(params[:user])
        format.html { redirect_to @user, notice: 'User was successfully updated.' }
        format.json { head :no_content }
      else
        format.html { render action: "edit" }
        format.json { render json: @user.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /users/1
  # DELETE /users/1.json
  def destroy
    @user = User.find(params[:id])
    @user.destroy

    respond_to do |format|
      format.html { redirect_to users_url }
      format.json { head :no_content }
    end
  end
end
But if we only need HTML and no JSON, then the file could also look like this:
class UsersController < ApplicationController
  def index
    @users = User.all
  end

  def show
    @user = User.find(params[:id])
  end

  def new
    @user = User.new
  end

  def edit
    @user = User.find(params[:id])
  end

  def create
    @user = User.new(params[:user])

    if @user.save
      redirect_to @user, notice: 'User was successfully created.'
    else
      render action: "new"
    end
  end

  def update
    @user = User.find(params[:id])

    if @user.update_attributes(params[:user])
      redirect_to @user, notice: 'User was successfully updated.'
    else
      render action: "edit"
    end
  end

  def destroy
    @user = User.find(params[:id])
    @user.destroy

    redirect_to users_url
  end
end
The original template used by rails generate scaffold for generating the controller can be found in the Rails Github repository at https://github.com/rails/rails/blob/3-2-stable/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb
It is a normal ERB file that you can download and then save as new file lib/templates/rails/scaffold_controller/controller.rb (you may need to create the corresponding directories manually). To get the above desired result, you need to change the template as follows:
<% if namespaced? -%>
require_dependency "<%= namespaced_file_path %>/application_controller"

<% end -%>
<% module_namespacing do -%>
class <%= controller_class_name %>Controller < ApplicationController
  def index
    @<%= plural_table_name %> = <%= orm_class.all(class_name) %>
  end

  def show
    @<%= singular_table_name %> = <%= orm_class.find(class_name, "params[:id]") %>
  end

  def new
    @<%= singular_table_name %> = <%= orm_class.build(class_name) %>
  end

  def edit
    @<%= singular_table_name %> = <%= orm_class.find(class_name, "params[:id]") %>
  end

  def create
    @<%= singular_table_name %> = <%= orm_class.build(class_name, "params[:#{singular_table_name}]") %>

    if @<%= orm_instance.save %>
      redirect_to @<%= singular_table_name %>, <%= key_value :notice, "'#{human_name} was successfully created.'" %>
    else
      render <%= key_value :action, '"new"' %>
    end
  end

  def update
    @<%= singular_table_name %> = <%= orm_class.find(class_name, "params[:id]") %>

    if @<%= orm_instance.update_attributes("params[:#{singular_table_name}]") %>
      redirect_to @<%= singular_table_name %>, <%= key_value :notice, "'#{human_name} was successfully updated.'" %>
    else
      render <%= key_value :action, '"edit"' %>
    end
  end

  def destroy
    @<%= singular_table_name %> = <%= orm_class.find(class_name, "params[:id]") %>
    @<%= orm_instance.destroy %>

    redirect_to <%= index_helper %>_url
  end
end
<% end -%>
Each time you now use rails generate scaffold, you get the controller in the variation you want.

Model Template

The basic idea is the same as with the controller in the section called “Scaffold Controller Template”: it's all about adapting the model created by the Rails generator to your own needs. The model template used by rails generate model and therefore also by rails generate scaffold can be found in the Rails Github repository at https://github.com/rails/rails/blob/3-2-stable/activerecord/lib/rails/generators/active_record/model/templates/model.rb.
Save this file in your Rails project under lib/templates/active_record/model/model.rb. If you want to edit the method to_s per default, your model.rb could for example look like this:
<% module_namespacing do -%>
class <%= class_name %> < <%= parent_class_name.classify %>
<% attributes.select {|attr| attr.reference? }.each do |attribute| -%>
  belongs_to :<%= attribute.name %><%= ', polymorphic: true' if attribute.polymorphic? %>
<% end -%>
<% if !accessible_attributes.empty? -%>
  attr_accessible <%= accessible_attributes.map {|a| ":#{a.name}" }.sort.join(', ') %>
<% else -%>
  # attr_accessible :title, :body
<% end -%>

  def to_s
    <%- if attributes.map{ |a| a.name }.include?('name') -%>
    name
    <%- else -%>
    "<%= class_name %> #{id}"
    <%- end -%>
  end

end
<% end -%>
If you now create a new model with rails generate model Book name number_of_pages:integer, the file app/models/book.rb will look like this:
class Book < ActiveRecord::Base
  attr_accessible :name, :number_of_pages

  def to_s
    name
  end

end

Updates about this book will be published on my Twitter feed.