Neu: Das englische Ruby on Rails 4.0 Buch.

5.7. Wann sollte man Scaffolding benutzen?

Die Verwendung von Scaffolding sollte nie Selbstzweck sein. Es gibt sehr viele Rails-Entwickler, die nie Scaffolding benutzen und immer alles selber von Hand aufbauen. Ich finde Scaffolds für einen schnellen Einstieg in ein neues Projekt ganz praktisch. Aber es ist immer nur der Anfang.

Beispiel für ein Minimal-Projekt

Nehmen wir einmal an, wir bräuchten auf die Schnelle eine Webseite, mit der man Kanzler auflisten und einzeln darstellen kann. Aber es würde keine Editier- oder Löschfunktion benötigt werden. In diesem Fall wäre ein Großteil des mit Scaffold angelegten Codes unnütz und müsste gelöscht werden. Probieren wir es nachfolgend aus:
MacBook:~ xyz$ rails new history2  
[...]
MacBook:~ xyz$ cd history2
MacBook:history2 xyz$ rails generate scaffold chancellor first_name last_name birthday:date day_of_death:date inauguration:date
[...]
MacBook:history2 xyz$ rake db:migrate
[...]
MacBook:history2 xyz$
Jetzt die db/seeds.rb mit den ersten sechs Kanzlern anlegen:
Chancellor.create(:first_name => 'Konrad', :last_name => 'Adenauer', :birthday => '05.01.1876', :day_of_death => '19.04.1967', :inauguration => '15.09.1949')
Chancellor.create(:first_name => 'Ludwig', :last_name => 'Erhard', :birthday => '04.02.1897', :day_of_death => '05.05.1977', :inauguration => '16.10.1963')
Chancellor.create(:first_name => 'Kurt Georg', :last_name => 'Kiesinger', :birthday => '06.04.1904', :day_of_death => '09.03.1988', :inauguration => '01.12.1966')
Chancellor.create(:first_name => 'Willy', :last_name => 'Brandt', :birthday => '18.12.1913', :day_of_death => '08.10.1992', :inauguration => '21.10.1969')
Chancellor.create(:first_name => 'Walter', :last_name => 'Scheel', :birthday => '08.09.1919', :inauguration => '07.05.1974')
Chancellor.create(:first_name => 'Helmut', :last_name => 'Schmidt', :birthday => '23.12.1918', :inauguration => '16.05.1974')
Und diese Daten einspielen:
MacBook:history2 xyz$ rake db:seed
MacBook:history2 xyz$
Da wir nur index und show benötigen, sollten wir die nicht benötigten Views löschen:
MacBook:history2 xyz$ rm app/views/chancellors/_form.html.erb 
MacBook:history2 xyz$ rm app/views/chancellors/new.html.erb 
MacBook:history2 xyz$ rm app/views/chancellors/edit.html.erb 
MacBook:history2 xyz$
Die Datei app/controllers/chancellors_controller.rb können wir mit einem Editor vereinfachen. Sie muss so aussehen:
class ChancellorsController < ApplicationController
  # GET /chancellors
  def index
    @chancellors = Chancellor.all
  end

  # GET /chancellors/1
  def show
    @chancellor = Chancellor.find(params[:id])
  end
end
Da wir nur HTML und keine JSON-Ausgabe benötigen, können wir uns das respond_to do |format| Konstrukt sparen. Rails wird dann automatisch HTML rendern.
Wir brauchen nur die Routen für index und show. Bitte öffnen Sie die Datei config/routes.rb und ändern Sie sie wie folgt ab:
History2::Application.routes.draw do
  resources :chancellors, :only => [ :index, :show ]
end
Ein rake routes zeigt uns, dass wirklich nur noch index und show geroutet werden:
MacBook:history2 xyz$ rake routes
chancellors GET /chancellors(.:format)     chancellors#index
 chancellor GET /chancellors/:id(.:format) chancellors#show
MacBook:history2 xyz$
Wenn wir jetzt mit rails server den Server starten und die URL http://0.0.0.0:3000/chancellors aufrufen, bekommen wir eine Fehlermeldung:
MacBook:history2 xyz$ rails server
=> Booting WEBrick
=> Rails 3.2.3 application starting in development on http://0.0.0.0:3000
=> Call with -d to detach
=> Ctrl-C to shutdown server
[2012-05-08 22:46:28] INFO  WEBrick 1.3.1
[2012-05-08 22:46:28] INFO  ruby 1.9.3 (2012-04-20) [x86_64-darwin11.3.0]
[2012-05-08 22:46:28] INFO  WEBrick::HTTPServer#start: pid=43440 port=3000


Started GET "/chancellors" for 127.0.0.1 at 2012-05-08 22:46:41 +0200
Processing by ChancellorsController#index as HTML
  Chancellor Load (0.1ms)  SELECT "chancellors".* FROM "chancellors" 
  Rendered chancellors/index.html.erb within layouts/application (17.6ms)
Completed 500 Internal Server Error in 81ms

ActionView::Template::Error (undefined method `edit_chancellor_path' for #<#<Class:0x007fc9150437c0>:0x007fc915047b18>):
    20:     <td><%= chancellor.day_of_death %></td>
    21:     <td><%= chancellor.inauguration %></td>
    22:     <td><%= link_to 'Show', chancellor %></td>
    23:     <td><%= link_to 'Edit', edit_chancellor_path(chancellor) %></td>
    24:     <td><%= link_to 'Destroy', chancellor, confirm: 'Are you sure?', method: :delete %></td>
    25:   </tr>
    26: <% end %>
  app/views/chancellors/index.html.erb:23:in `block in _app_views_chancellors_index_html_erb__3473545449794762094_70250803843160'
  app/views/chancellors/index.html.erb:15:in `each'
  app/views/chancellors/index.html.erb:15:in `_app_views_chancellors_index_html_erb__3473545449794762094_70250803843160'


  Rendered /Users/xyz/.rvm/gems/ruby-1.9.3-p194/gems/actionpack-3.2.3/lib/action_dispatch/middleware/templates/rescues/_trace.erb (27.7ms)
  Rendered /Users/xyz/.rvm/gems/ruby-1.9.3-p194/gems/actionpack-3.2.3/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (1.5ms)
  Rendered /Users/xyz/.rvm/gems/ruby-1.9.3-p194/gems/actionpack-3.2.3/lib/action_dispatch/middleware/templates/rescues/template_error.erb within rescues/layout (40.6ms)
Die Fehlermeldung sagt, dass wir im View app/views/chancellors/index.html.erb eine Methode edit_chancellor_path aufrufen. Da wir aber nur noch index und show routen, gibt es keine edit-, destroy- oder new-Methoden mehr. Wir müssen entsprechend die Datei app/views/chancellors/index.html.erb im Editor wie folgt anpassen:
<h1>Listing chancellors</h1>

<table>
  <tr>
    <th>First name</th>
    <th>Last name</th>
    <th>Birthday</th>
    <th>Day of death</th>
    <th>Inauguration</th>
    <th></th>
  </tr>

<% @chancellors.each do |chancellor| %>
  <tr>
    <td><%= chancellor.first_name %></td>
    <td><%= chancellor.last_name %></td>
    <td><%= chancellor.birthday %></td>
    <td><%= chancellor.day_of_death %></td>
    <td><%= chancellor.inauguration %></td>
    <td><%= link_to 'Show', chancellor %></td>
  </tr>
<% end %>
</table>
Und wo wir schon gerade dabei sind, ändern wir auch noch die app/views/chancellors/show.html.erb entsprechend ab:
<p>
  <b>First name:</b>
  <%= @chancellor.first_name %>
</p>

<p>
  <b>Last name:</b>
  <%= @chancellor.last_name %>
</p>

<p>
  <b>Birthday:</b>
  <%= @chancellor.birthday %>
</p>

<p>
  <b>Day of death:</b>
  <%= @chancellor.day_of_death %>
</p>

<p>
  <b>Inauguration:</b>
  <%= @chancellor.inauguration %>
</p>
Jetzt ist unsere Applikation fertig. Starten Sie den Rails-Server mit rails server und öffnen Sie die URL http://0.0.0.0:3000/chancellors im Browser.

Anmerkung

Bei diesem Beispiel gehe ich nicht auf notwendige Veränderungen in den Tests ein, da dies keine Übung zum Test-Driven-Development ist, sondern eine Arbeitsweise mit Scaffolding aufzeigen soll. TDD-Entwickler werden schnell die Tests anpassen können.

Fazit

Probieren Sie es aus. Arbeiten Sie einmal mit Scaffolds und einmal ohne. Dann werden Sie schnell ein Gefühl dafür bekommen, ob es in Ihre Arbeitsweise passt oder nicht. Ich empfinde Scaffolding als Arbeitserleichterung für Standard-Applikationen.

Autor

Stefan Wintermeyer