5.3. When Should You Use Scaffolding?

You should never use scaffolding just for the sake of it. There are Rails developers who never use scaffolding and always build everything manually. I find scaffolding quite useful for quickly getting into a new project. But it is always just the beginning.

Example for a Minimal Project

Let's assume we need a web page quickly with which we can list products and represent them individually. But we do not require an editing or deleting function. In that case, a large part of the code created via scaffold would be useless and have to be deleted. Let's try it out as follows:
$ rails new read-only-shop
  [...]
$ cd read-only-shop 
$ rails generate scaffold product name 'price:decimal{7,2}'
      invoke  active_record
      create    db/migrate/20121121115005_create_products.rb
      create    app/models/product.rb
      invoke    test_unit
      create      test/unit/product_test.rb
      create      test/fixtures/products.yml
      invoke  resource_route
       route    resources :products
      invoke  scaffold_controller
      create    app/controllers/products_controller.rb
      invoke    erb
      create      app/views/products
      create      app/views/products/index.html.erb
      create      app/views/products/edit.html.erb
      create      app/views/products/show.html.erb
      create      app/views/products/new.html.erb
      create      app/views/products/_form.html.erb
      invoke    test_unit
      create      test/functional/products_controller_test.rb
      invoke    helper
      create      app/helpers/products_helper.rb
      invoke      test_unit
      create        test/unit/helpers/products_helper_test.rb
      invoke  assets
      invoke    coffee
      create      app/assets/javascripts/products.js.coffee
      invoke    scss
      create      app/assets/stylesheets/products.css.scss
      invoke  scss
      create    app/assets/stylesheets/scaffolds.css.scss
$ rake db:migrate
  [...]
$
Now create the db/seeds.rb with some demo products:
Product.create(name: 'Apple', price: 1)
Product.create(name: 'Orange', price: 1)
Product.create(name: 'Pineapple', price: 2.4)
Product.create(name: 'Marble cake', price: 3)
And populate it with this data:
$ rake db:seed
$
As we only need index and show, we should delete the not required views:
$ rm app/views/products/_form.html.erb 
$ rm app/views/products/new.html.erb 
$ rm app/views/products/edit.html.erb 
$ 
The file app/controllers/products_controller.rb can be simplified with an editor. It should look like this:
class ProductsController < ApplicationController
  # GET /products
  def index
    @products = Product.all
  end

  # GET /products/1
  def show
    @product = Product.find(params[:id])
  end
end
As we only need HTML and not JSON output, we can manage without the respond_to do |format| construct. Rails then automatically renders HTML.
We only need the routes for index and show. Please open the file config/routes.rb and edit it as follows:
ReadOnlyShop::Application.routes.draw do
  resources :products, :only => [:index, :show]
end 
A rake routes shows us that really only index and show are routed now:
$ rake routes
products GET /products(.:format)     products#index
 product GET /products/:id(.:format) products#show
$ 
If we now start the server rails server and go to the URL http://0.0.0.0:3000/products, we get an error message.
Error message
The same message will be displayed in the log:
$ rails server
=> Booting WEBrick
=> Rails 3.2.9 application starting in development on http://0.0.0.0:3000
=> Call with -d to detach
=> Ctrl-C to shutdown server
[2012-11-21 12:56:21] INFO  WEBrick 1.3.1
[2012-11-21 12:56:21] INFO  ruby 1.9.3 (2012-11-10) [x86_64-darwin12.2.1]
[2012-11-21 12:56:21] INFO  WEBrick::HTTPServer#start: pid=51640 port=3000


Started GET "/products" for 127.0.0.1 at 2012-11-21 12:56:24 +0100
Connecting to database specified by database.yml
Processing by ProductsController#index as HTML
  Product Load (0.1ms)  SELECT "products".* FROM "products" 
  Rendered products/index.html.erb within layouts/application (18.8ms)
Completed 500 Internal Server Error in 82ms

ActionView::Template::Error (undefined method `edit_product_path' for #<#<Class:0x007f832f282698>:0x007f832f287af8>):
    14:     <td><%= product.name %></td>
    15:     <td><%= product.price %></td>
    16:     <td><%= link_to 'Show', product %></td>
    17:     <td><%= link_to 'Edit', edit_product_path(product) %></td>
    18:     <td><%= link_to 'Destroy', product, method: :delete, data: { confirm: 'Are you sure?' } %></td>
    19:   </tr>
    20: <% end %>
  app/views/products/index.html.erb:17:in `block in _app_views_products_index_html_erb__2795156989031928261_70100690456940'
  app/views/products/index.html.erb:12:in `each'
  app/views/products/index.html.erb:12:in `_app_views_products_index_html_erb__2795156989031928261_70100690456940'


  Rendered /Users/xyz/.rvm/gems/ruby-1.9.3-p327/gems/actionpack-3.2.9/lib/action_dispatch/middleware/templates/rescues/_trace.erb (1.9ms)
  Rendered /Users/xyz/.rvm/gems/ruby-1.9.3-p327/gems/actionpack-3.2.9/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (1.3ms)
  Rendered /Users/xyz/.rvm/gems/ruby-1.9.3-p327/gems/actionpack-3.2.9/lib/action_dispatch/middleware/templates/rescues/template_error.erb within rescues/layout (13.9ms)
The error message states that we call an undefined method edit_product_path in the view app/views/products/index.html.erb. As we only route index and show now, there are no more edit, destroy or new methods any more. So we need to adapt the file app/views/products/index.html.erb in the editor as follows:
<h1>Listing products</h1>

<table>
  <tr>
    <th>Name</th>
    <th>Price</th>
    <th></th>
  </tr>

<% @products.each do |product| %>
  <tr>
    <td><%= product.name %></td>
    <td><%= product.price %></td>
    <td><%= link_to 'Show', product %></td>
  </tr>
<% end %>
</table>
And while we are at it, we also edit the app/views/products/show.html.erb accordingly:
<p id="notice"><%= notice %></p>

<p>
  <b>Name:</b>
  <%= @product.name %>
</p>

<p>
  <b>Price:</b>
  <%= @product.price %>
</p>

<%= link_to 'Back', products_path %>
Now our application is finished. Start the Rails server with rails server and open the URL http://0.0.0.0:3000/products in the browser.
Index View

Note

In this example, I am not commenting on the required changes in the tests, as this is not an exercise for test driven development but meant to demonstrate a way of working with scaffolding. TDD developers will quickly be able to adapt the tests.

Conclusion

Have a go and try it out. Try working with scaffolds one time and without them the next. Then you will soon get a feel for whether it fits into your working method or not. I find that scaffolding makes my work much easier for standard applications.

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