Neu: Das englische Ruby on Rails 4.0 Buch.

5.6. Die Views

Jetzt starten wir den Rails-Webserver:
MacBook:history 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 19:26:14] INFO  WEBrick 1.3.1
[2012-05-08 19:26:14] INFO  ruby 1.9.3 (2012-04-20) [x86_64-darwin11.3.0]
[2012-05-08 19:26:14] INFO  WEBrick::HTTPServer#start: pid=43118 port=3000

Anmerkung

Falls Sie jetzt eine Warnung Ihrer eingebauten Firewall bekommen, zeigt dies, dass Sie Kapitel 3, Erste Schritte mit Rails nicht durchgearbeitet haben. ;-)
Jetzt ein kleiner Trommelwirbel … Spannung … den Webbrowser starten und die URL http://0.0.0.0:3000/chancellors aufrufen. Sie sehen die Liste der Bundeskanzler als einfache Webseite.
Index der eingetragenen Bundeskanzler
Wenn Sie jetzt auf den Link „New Chancellor“ klicken, dann bekommen Sie ein Eingabeformular für einen neuen Datensatz angezeigt:
Eingabeformular für einen neuen Datensatz
Gehen Sie mit dem Back-Button Ihres Browsers wieder zurück und klicken Sie auf den „Show“-Link in der Zeile von Konrad Adenauer. Sie sehen daraufhin folgende Seite:
Anzeige eines einzelnen Datensatzes
Wenn Sie jetzt auf „Edit“ klicken, bekommen Sie die Editieransicht zu diesem Datensatz:
Editier-Formular für einen bestehenden Datensatz
Und wenn Sie auf der Index-Seite auf „Destroy“ klicken, können Sie nach einer Bestätigungsabfrage einen Datensatz löschen. Ist das cool?! Sie haben innerhalb von nicht mal 10 Minuten eine Web-Applikation geschrieben, mit der Sie Datensätze anlegen (create), auflisten und anschauen (read/retrieve), bearbeiten (update) und löschen (delete/destroy) können (CRUD). Das ist der Zauber von Scaffolding.

Wo liegen die Views?

Sie werden es sich schon denken können, aber schauen wir uns trotzdem das Verzeichnis app/views/chancellors an:
MacBook:history xyz$ ls app/views/chancellors 
_form.html.erb
edit.html.erb
index.html.erb
new.html.erb
show.html.erb
MacBook:history xyz$
Für index, edit, new und show liegen dort die entsprechenden Views. Da new und edit beide ein Formular zum Bearbeiten der Daten benötigen, wird dieses im Sinne von DRY (Don't Repeat Yourself) im Partial _form.html.erb abgelegt (siehe „Partials“) und in new.html.erb und edit.html.erb mit einem <%= render 'form' %> eingebunden.
Öffnen wir einmal die Datei app/views/chancellors/index.html.erb:
<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>
    <th></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>
    <td><%= link_to 'Edit', edit_chancellor_path(chancellor) %></td>
    <td><%= link_to 'Destroy', chancellor, confirm: 'Are you sure?', method: :delete %></td>
  </tr>
<% end %>
</table>

<br />

<%= link_to 'New Chancellor', new_chancellor_path %>
Als mittlerweiler alter ERB-Hase werden Sie keine Probleme haben, den Code zu lesen und zu verstehen. Falls doch, empfehle ich noch mal einen schnellen Blick in „Programmieren in einer erb-Datei“.

form_for

Im vom new und edit View benutzten Partial app/views/chancellors/_form.html.erb finden Sie folgenden Code für das Chancellor-Formular:
<%= form_for(@chancellor) do |f| %>
  <% if @chancellor.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@chancellor.errors.count, "error") %> prohibited this chancellor from being saved:</h2>

      <ul>
      <% @chancellor.errors.full_messages.each do |msg| %>
        <li><%= msg %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    <%= f.label :first_name %><br />
    <%= f.text_field :first_name %>
  </div>
  <div class="field">
    <%= f.label :last_name %><br />
    <%= f.text_field :last_name %>
  </div>
  <div class="field">
    <%= f.label :birthday %><br />
    <%= f.date_select :birthday %>
  </div>
  <div class="field">
    <%= f.label :day_of_death %><br />
    <%= f.date_select :day_of_death %>
  </div>
  <div class="field">
    <%= f.label :inauguration %><br />
    <%= f.date_select :inauguration %>
  </div>
  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>
Der Helper form_for kümmert sich in einem Block für Sie um die Erstellung des HTML-Formulars, mit dem der User die Daten für den Datensatz eingeben oder verändern kann. Wenn Sie hier ein <div class="field">-Element löschen, dann kann dies nicht mehr zur Eingabe im Web-Interface benutzt werden. Ich gehe an dieser Stelle nicht auf alle möglichen Form-Feld-Varianten ein. Die häufig benötigten werde ich bei späteren Beispielen benutzen und (falls sie nicht selbsterklärend sind) erklären.

Anmerkung

Einen Überblick zu allen Form-Helpers finden Sie unter http://guides.rubyonrails.org/form_helpers.html.
Bei der Verwendung von Validierungen im Model werden auftretende Validierungsfehler im folgenden Code am Kopf des Formulars angezeigt:
  <% if @chancellor.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@chancellor.errors.count, "error") %> prohibited this chancellor from being saved:</h2>

      <ul>
      <% @chancellor.errors.full_messages.each do |msg| %>
        <li><%= msg %></li>
      <% end %>
      </ul>
    </div>
  <% end %>
Ein solcher Fehler würde dann vom Controller bemerkt und per Flash-Message wie folgt auf der Webseite angezeigt.
Flash-Error für einen neuen Datensatz

Zugriff per XML oder JSON

Rails' Scaffolding generiert per Default nicht nur den Zugriff per HTML für „menschliche“ Benutzer, sondern auch direkt noch eine Schnittstelle für Automaten. Damit lassen sich die gleichen Methoden index, show, new, create, update und destroy aufrufen. Eben nur in einem für eine Maschine einfacheren Format. Beispielhaft besprechen wir hier die index-Action, mit der alle Daten auf einmal ausgelesen werden. Über die gleiche Idee können aber auch Daten gelöscht (destroy) oder geändert (update) werden.
Wenn Sie keinen maschinellen Zugriff auf Daten benötigen, können Sie diese Beispiele überspringen. Sie sollten dann aber auch sicherheitshalber alle Zeilen mit format.xml bzw. format.json in den respond_to-Blöcken in Ihren Controllern löschen. Ansonsten haben Sie eine Schnittstelle zu den Daten, die Sie vielleicht irgendwann mal vergessen und die eine potenzielle Sicherheitslücke darstellen.

JSON als Default

Ganz am Anfang von app/controllers/chancellors_controller.rb finden Sie den Eintrag für die index-Action:
class ChancellorsController < ApplicationController
  # GET /chancellors
  # GET /chancellors.json
  def index
    @chancellors = Chancellor.all

    respond_to do |format|
      format.html # index.html.erb
      format.json { render json: @chancellors }
    end
  end
[...]
Der Code ist übersichtlich. In der Instanz-Variable @chancellors werden alle Bundeskanzler abgespeichert. Danach wird irgendetwas mit einem Format gemacht. Hmmm … da steht was von json. Probieren wir mal Folgendes aus: Bitte starten Sie mit rails server wieder den Rails-Server und gehen Sie mit Ihrem Webbrowser auf die URL http://0.0.0.0:3000/chancellors.json. Heureka! Sie bekommen folgende Ansicht:
Index-JSON-Anzeige
Die URL http://0.0.0.0:3000/chancellors.json gibt uns alle Kanzler im JSON-Format aus. In Rails 3.0 war hier der Default noch XML. Ob XML oder JSON ist aber eigentlich auch egal. Die coolen JavaScript-Programmierer haben halt lieber JSON und da ja heute an jeder Ecke ein AJAX-Element eingebaut wird, lag der Schritt nahe, den Default von XML auf JSON zu ändern.
Wenn Sie keine JSON-Ausgabe wünschen, müssen Sie diese Zeile in der app/controllers/chancellors_controller.rb löschen.

JSON und XML zusammen

Wenn Sie in einer Rails-Applikation einmal eine JSON- und eine XML-Schnittstelle benötigen, so müssen Sie im Controller einfach nur beide Varianten im respond_to-Block angeben. Hier ein Beispiel mit der app/controllers/chancellors_controller.rb in der index-Action:
class ChancellorsController < ApplicationController
  # GET /chancellors
  # GET /chancellors.json
  def index
    @chancellors = Chancellor.all

    respond_to do |format|
      format.html # index.html.erb
      format.json { render json: @chancellors }
      format.xml { render xml: @chancellors }
    end
  end
[...]

Autor

Stefan Wintermeyer