Rheinwerk Computing < openbook > Rheinwerk Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

Inhaltsverzeichnis
Geleitwort des Fachgutachters
Einleitung
1 Einführung
2 Installation
3 Erste Schritte
4 Einführung in Ruby
5 Eine einfache Bookmarkverwaltung
6 Test-Driven Development
7 Rails-Projekte erstellen
8 Templatesystem mit ActionView
9 Steuerzentrale mit ActionController
10 Datenbankzugriff mit ActiveRecord
11 E-Mails verwalten mit ActionMailer
12 Nützliche Helfer mit ActiveSupport
13 Ajax on Rails
14 RESTful Rails und Webservices
15 Rails mit Plug-ins erweitern
16 Performancesteigerung
17 Sicherheit
18 Veröffentlichen einer Rails-Applikation auf einem Server
Ihre Meinung?

Spacer
 <<   zurück
Ruby on Rails 2 von Hussein Morsy, Tanja Otto
Das Entwickler-Handbuch
Buch: Ruby on Rails 2

Ruby on Rails 2
geb., mit DVD
699 S., 39,90 Euro
Rheinwerk Computing
ISBN 978-3-89842-779-1
Online bestellenPrint-Version Jetzt Buch bestellen
* versandkostenfrei in (D) und (A)
Pfeil 8 Templatesystem mit ActionView
  Pfeil 8.1 ERB-Templates
  Pfeil 8.2 Erstellung von Templates
  Pfeil 8.3 Helper
  Pfeil 8.4 Layouts
  Pfeil 8.5 Formulare
  Pfeil 8.6 Partials
  Pfeil 8.7 Alternative Template-Systeme


Rheinwerk Computing - Zum Seitenanfang

8.5 Formulare  Zur nächsten ÜberschriftZur vorigen Überschrift

Formulare begleiten uns täglich bei der Arbeit. Benutzer müssen sich an unseren Applikationen anmelden können, über ein Suchformular nach Inhalten suchen können, oder die Daten in den Datenbanken unserer Applikationen müssen gepflegt werden.

In Rails werden zwei Arten von Formularen unterschieden:

  • Formulare mit Bezug zu einem Model
  • Formulare ohne Bezug zu einem Model

Rheinwerk Computing - Zum Seitenanfang

Formulare mit Bezug zu einem Model  Zur nächsten ÜberschriftZur vorigen Überschrift

Datensätze bearbeiten

Formulare mit Bezug zu einem Model dienen dazu, neue Datensätze in der Datenbank anzulegen oder bestehende Datensätze zu bearbeiten. Ihre Felder entsprechen den Attributen des Models. Wir haben solche Formulare bei der Erstellung unserer Beispiel-Applikation employees in Kapitel »Erste Schritte« kennengelernt. Als wir mit Hilfe des scaffold -Generators die Ressource Employee erzeugt haben, hat uns der Generator automatisch Formulare zum Anlegen und Editieren von Mitarbeitern in den Templates new.html.erb und edit.html.erb erzeugt.

Obwohl beide Formulare die gleichen Formularelemente haben, unterscheiden sie sich in zwei Dingen: Zum einen werden die Formulardaten an unterschiedliche Adressen geschickt, zum anderen müssen zum Editieren eines Datensatzes die Formularfelder mit den Werten des zu editierenden Datensatzes vorbelegt werden.

Helper

Rails stellt uns viele Helper-Methoden zur Verfügung, die uns das Erstellen von Formularen, die auf Models zugreifen, sehr einfach machen.

Damit ein Formular mit Bezug zu einem Model funktioniert, müssen die erforderlichen Daten vom Controller zur Verfügung gestellt werden. Wie das idealerweise geschieht, können Sie sehr gut anhand der Controller sehen, die beim Erzeugen einer Ressource automatisch von Rails generiert werden.

Bevor das Formular zum Anlegen eines neuen Mitarbeiters angezeigt wird, wird im Employees-Controller die Action new ausgeführt, die ein neues Objekt der Klasse Employee erzeugt und dieses als Instanzvariable zur Verfügung stellt:

Listing  Action new in app/controllers/employees_controller.rb

def new
  @employee = Employee.new
  ...
end

Bevor das Formular zum Editieren eines Mitarbeiters angezeigt wird, wird im Employees-Controller die Action edit ausgeführt, die den zu editierenden Datensatz anhand der ID aus der Datenbank ausliest und ihn auch als Instanzvariable zur Verfügung stellt:

Listing  Action edit in app/controllers/employees_controller.rb

def edit
  @employee = Employee.find(params[:id])
end

form_for

Erzeugung von Formularen

Zur Erzeugung von Formularen mit Bezug zu einem Model stellt uns Rails die Helper-Methode form_for zur Verfügung. Neu in Rails 2 ist, dass dieser Methode »nur« noch das Objekt, das in den Actions new und edit erzeugt wurde, übergeben werden muss. Die Methode erkennt, ob es sich dabei um ein neues Objekt oder ein Objekt, das editiert werden soll, handelt und setzt das Attribut action innerhalb des von ihr generierten form -Tags in Abhängigkeit davon.

<% form_for(@employee) do |f| %>
...
<% end %>

In Abhängigkeit vom Zustand des übergebenen Objekts macht Rails daraus folgendes:

  • @employee ist ein neues Objekt und soll mit neuen Werten gefüllt werden:
    <% form_for :employee, @employee, :url => employee_path,
      :html => { :class => "new_employee",
      :id => "new_employee" } do |f| %>
        ...
    <% end %>
    Zum Anlegen eines Mitarbeiters in unserer Beispiel-Applikation wird folgender HTML-Code generiert:

    Listing  Auszug aus HTML-Code http://localhost:3000/employees/new

    <form action="/employees" class="new_employee"
          id="new_employee" method="post">
       ...
    </form>
  • @employee ist bereits gespeichert und soll bearbeitet werden:
    <% form_for :employee, @employee,
    	    :url => employee_path(@employee),
    :html => { :method => :put, :class => "edit_employee",
    :id => "edit_employee_1" } do |f| %>
         ...
    <% end %>
    Zum Editieren eines Mitarbeiters in unserer Beispiel-Applikation wird folgender HTML-Code generiert:
    <form action="/employees/1" class="edit_employee"
           id="edit_employee_1" method="post">
       <input name="_method" type="hidden" value="put" />
      ...
    </form>

    Listing  Auszug aus HTML-Code http://localhost:3000/employees/1/edit

    Da Webrowser nicht die HTTP-Methode PUT unterstützen, wird ein verstecktes Feld generiert, das angibt, dass es sich um die PUT-Methode handelt.

Formularelemente

Die einzelnen Formularelemente werden innerhalb eines Blocks erzeugt, der der Helper-Methode form_for übergeben wird. Rails stellt dazu weitere Helper-Methoden zur Verfügung, die als Parameter immer den Namen des Feldes im Model erwarten, für dessen Erzeugung oder Bearbeitung das jeweilige Formularfeld zuständig ist. Damit Rails weiß, für welches Objekt die einzelnen Formularelemente erzeugt werden, werden die Helper-Methoden auf die Blockvariable, in unserem Beispiel f, angewendet.

Der Name der von den Helper-Methoden generierten HTML-Tags für die Formularelemente setzt sich zusammen aus dem Namen des Objekts, das als Parameter an die Methode form_for übergeben wurde, gefolgt von dem übergebenen Feldnamen in eckigen Klammern:

<input id="employee_firstname" name="employee[firstname] " />

Warum das so ist, bzw. den Trick an dem Ganzen, erkennen wir, wenn wir uns ansehen, was passiert, wenn das Formular ausgefüllt abgeschickt wird. Die Werte aus einem Formular werden immer als Hash an den Controller, der das Formular verarbeitet, gesendet. Auf diesen Hash kann innerhalb des Controllers mit Hilfe von params[:feldname] zugegriffen werden. Beinhaltet der Feldname im Formular eine eckige Klammer, macht Rails daraus wieder einen Hash. Das heißt, auf den Wert aus dem Feld »firstname« könnte der Controller wie folgt zugreifen:

params[:employee][:firstname]

Das wiederum bedeutet, dass sich innerhalb des Hashs params[:employee] der Hash mit allen Werten aus dem Formular befindet:

{:firstname => 'Lee', :lastname => 'Adama', ...\ 

Und genau dieser Hash wird im Controller innerhalb der Action create, die für die Verarbeitung des Formulars zum Anlegen eines neuen Mitarbeiters verantwortlich ist, an die Methode new des Models Employee übergeben:

Listing  Action create in app/controllers/employees_controller.rb

def create
  @employee = Employee.new(params[:employee])

  ...
end

Den einzelnen Helper-Methoden zum Erzeugen der Formularfelder können Sie zusätzlich HTML-Optionen übergeben, um zum Beispiel die Größe eines Textfeldes zu bestimmen. In den folgenden Abschnitten werden wir Ihnen die einzelnen Helper-Methoden mit den zur Verfügung stehenden HTML-Optionen vorstellen.

Einzeilige Textfelder

text_field

Zum Erzeugen eines einzeiligen Textfeldes steht die Helper-Methode text_field zur Verfügung, der Sie folgende HTML-Optionen übergeben können:

  • :size
    Anzahl der Zeichen, die ein Textfeld breit sein soll. Wird diese Option nicht angegeben, wird standardmäßig ein Textfeld mit der Breite von 30 Zeichen erzeugt.
  • :maxlength
    Anzahl der Zeichen, die maximal eingegeben werden dürfen.
  • :class
    Angabe der CSS-Klasse, die zur Formatierung des Textfeldes genutzt werden soll.
  • :disabled
    Wenn true übergeben wird, wird das Textfeld deaktiviert.

Beispiel

Die Anwendung dieser HTML-Optionen am Beispiel des Textfeldes »firstname« in dem Formular zum Anlegen eines Mitarbeiters:

Listing  app/views/employees/new.html.erb

<% form_for(@employee) do |f| %>
  <p>
    <b>Firstname</b><br />
    <%= f.text_field :firstname, :size => 10,
				 :maxlength => 5,
				 :class => "eingabe",
				 :disabled => true %>
  </p>

  ...

<% end %>

Es wird folgender HTML-Code generiert:

<form action="/employees" class="new_employee"
      id="new_employee" method="post">
 <p>
 <b>Firstname</b><br />
 <input class="eingabe" disabled="disabled"
        id="employee_firstname" maxlength="5"
        name="employee[firstname]"
        size="10" type="text" />
</p>
</form>

Mehrzeilige Textfelder

text_area

Mehrzeilige Textfelder werden mit der Helper-Methode text_area erzeugt. Es stehen folgende HTML-Optionen zur Verfügung:

  • :cols
    Anzahl der Spalten, die ein mehrzeiliges Textfeld breit sein soll. Wird diese Option nicht angegeben, wird standardmäßig eine Textfeld mit der Breite von 40 Spalten erzeugt.
  • :rows
    Anzahl der Zeilen, die ein mehrzeiliges Textfeld hoch sein soll. Wird diese Option nicht angegeben, wird standardmäßig eine Textarea mit der Höhe von 20 Zeilen erzeugt.
  • :size
    Kurzschreibweise zur Angabe von cols und rows. Es wird ein Wert im Format »Breite«x»Höhe« zum Beispiel 12x4, übergeben.
  • :class
    Angabe der CSS-Klasse, die zur Formatierung des Textfeldes genutzt werden soll.
  • :disabled
    Wenn true übergeben wird, wird das Textfeld deaktiviert.

Beispiel

Diese HTML-Optionen können Sie zum Beispiel auf unser mehrzeiliges Textfeld comment in dem Formular zum Anlegen eines Mitarbeiters anwenden:

Listing  app/views/employees/new.html.erb

<% form_for(@employee) do |f| %>
  ...
  <p>
    <b>Comment</b><br />
    <%= f.text_area :comment, :size => "12x4" %>
  </p>
  ...
<% end %>

Daraus wird folgender HTML-Code erzeugt:

...
<p>
  <b>Comment</b><br />
  <textarea cols="12" id="employee_comment"
	    name="employee[comment]" rows="4">
  </textarea>
</p>
...
Datentypen string und text
Das mehrzeilige Textfeld comment in unserer Beispiel-Applikation employees wurde beim Generieren der Ressource employee von dem scaffold -Generator automatisch erzeugt, weil wir angegeben haben, das es sich beim Datentyp dieses Feldes um text handelt. Da text sehr viel mehr Zeichen verarbeiten kann, als der Datentyp string , erzeugt der Generator für Felder vom Typ string ein einzeiliges Textfeld und für Felder vom Typ text mehrzeilige Textfelder.

Passworteingabefelder

password_field

Passworteingabefelder werden in Formularen mit Bezug zu einem Model mit der Helper-Methode password_field erzeugt. Als HTML-Optionen stehen die selben zur Verfügung, wie für ein einzeiliges Textfeld:

  • :size
    Anzahl der Zeichen, die ein Passworteingabefeld breit sein soll. Wird diese Option nicht angegeben, wird standardmäßig ein Passworteingabefeld mit der Breite von 30 Zeichen erzeugt.
  • :maxlength
    Anzahl der Zeichen, die maximal eingegeben werden dürfen.
  • :class
    Angabe der CSS-Klasse, die zur Formatierung des Passworteingabefeldes genutzt werden soll.
  • :disabled
    Wenn true übergeben wird, wird das Passworteingabefeld deaktiviert.

Beispiel

Wir haben in unserem Model Employee kein Passwortfeld vorgesehen, trotzdem wollen wir Ihnen den Einsatz eines Passworteingabefeldes zeigen. Wir setzen anstelle des Textfeldes zur Eingabe des Nachnamens im Formular zum Anlegen eines Mitarbeiters ein Passworteingabefeld ein:

Listing  app/views/employees/new.html.erb

<% form_for(@employee) do |f| %>
  ...
  <p>
    <b>Lastname</b><br />
    <%= f.password_field :lastname, :size => 8,
			 :maxlength => 8 %>
  </p>
  ...
<% end %>

Es wird folgender HTML-Code erzeugt:

...
<p>
  <b>Lastname</b><br />
  <input id="employee_lastname" maxlength="8"
	 name="employee[lastname]"
	 size="8" type="password" />
</p>
...

Versteckte Felder

Versteckte Felder sind im Prinzip wie Textfelder, nur dass sie nicht angezeigt werden und deshalb keine Eingabe möglich ist. Aus diesem Grund müssen sie auch nicht mit Hilfe von HTML-Optionen verändert werden.

Der Wert eines versteckten Feldes wird zusammen mit den Werten der anderen Formularelemente übertragen. Versteckte Felder werden eingesetzt, um Zusatzinformationen, die nicht vom Benutzer eingegeben werden sollen, zu übermitteln.

hidden_field

Zur Erzeugung eines versteckten Feldes steht die Helper-Methode hidden_field zur Verfügung. Wir zeigen den Einsatz der Methode am Beispiel der Eingabe des Nachnamens im Formular zum Editieren eines Mitarbeiters:

Listing  app/views/employees/edit.html.erb

<% form_for(@employee) do |f| %>
  <p>
    <b>Lastname</b><br />
    <%= f.hidden_field :lastname %>
  </p>
  ...
<% end %>

Daraus wird folgender HTML-Code generiert:

...
<p>
  <b>Lastname</b><br />
  <input id="employee_lastname" name="employee[lastname]"
	 type="hidden" value="Adama" />
</p>
...

Absendebutton

submit

Zum Erzeugen eines Absendebuttons, der ein Formular abschickt, stellt uns Rails die Helper-Methode submit zur Verfügung, die die Beschriftung des Buttons als Parameter erwartet. In unserem Formular zum Editieren eines Mitarbeiters ist das der Wert »Update«.

Als HTML-Option steht :disabled => true zur Verfügung, um den Button zu deaktivieren:

Listing  app/views/employees/edit.html.erb

<% form_for(@employee) do |f| %>
  ...
  <p>
    <%= f.submit "Update", :disabled => true %>
  </p>
<% end %>

Rails erzeugt daraus folgenden HTML-Code:

<p>
  <input disabled="disabled" id="employee_submit"
	 name="commit" type="submit" value="Update" />
</p>

Beschriftung von Formularfeldern

Label

Da im modernen XHTML ein logischer Bezug zwischen der Beschriftung eines Formularelementes und dem Formularelement selbst bestehen soll, ist es nicht mehr ratsam, die Beschriftung einfach durch vorangestellten Text vorzunehmen, da dadurch eben dieser Bezug nicht hergestellt werden kann. Stattdessen wird empfohlen, zur Beschriftung von Formularelementen ein label -Tag zu verwenden.

Rails stellt uns dazu die Helper-Methode label zur Verfügung, die als Parameter den Namen des Feldes im Model erwartet, zu dessen Beschriftung das Label dienen soll. Optional kann noch ein Parameter für die Beschriftung selbst übergeben werden. Passiert das nicht, wird der Feldname mit führendem Großbuchstaben angezeigt.

Beispiel

Wir wollen den Einsatz der Methode label am Beispiel unseres Formulars zum Editieren eines Mitarbeiters zeigen:

Listing  app/views/employees/edit.html.erb

<h1>Editing employee</h1>

<%= error_messages_for :employee %>

<% form_for(@employee) do |f| %>
  <p>
    <%=f.label :firstname, "Vorname" %><br />
    <%= f.text_field :firstname, :size => 20 %>
  </p>

  <p>
    <%=f.label :lastname, "Nachname" %><br />
    <%= f.text_field :lastname, :size => 20 %>
  </p>
  ...
  <p>
    <%= f.submit "Update", :disabled => true %>
  </p>
<% end %>

<%= link_to 'Show', @employee %> |
<%= back_to_list %>

Im daraus generierten HTML-Code sieht man, dass der Bezug zwischen Label und Formularelement über das Attribut for im label -Tag hergestellt wird:

<form action="/employees/1" class="edit_employee"
      id="edit_employee_1" method="post">
  <p>
<label for="employee_firstname" >Vorname</label><br />
    <input id="employee_firstname" name="employee[firstname]"
	   size="20" type="text" value="Lee" />
  </p>

  <p>
    <label for="employee_lastname" >Nachname</label><br />
    <input id="employee_lastname" name="employee[lastname]"
	   size="20" type="text" value="Adama" />
  </p>
  ...
</form>

Die Formatierung der label -Tags kann mit Hilfe von CSS erfolgen.

Datei-Upload

file_field

Ein Formularelement zum Datei-Upload wird in Formularen mit Bezug zu einem Model mit der Helper-Methode file_field erzeugt, die wie alle anderen Helper-Methoden zur Generierung von Formularelementen den entsprechenden Namen des Feldes im Model als Parameter erwartet. Wir können Ihnen hier nur die Syntax der Methode zeigen, da unser Model nicht auf das Speichern von Dateien vorbereitet ist:

<%= f.file_field :image %>

Die Methode generiert ein Formularelement vom Typ file:

<input id="employee_image" name="employee[image]" size="30"
       type="file" />

Als HTML-Optionen stehen die selben, wie für ein einzeiliges Textfeld zur Verfügung:

  • :size
    Anzahl der Zeichen, die ein Datei-Upload-Feld breit sein soll. Wird diese Option nicht angegeben, wird standardmäßig ein Datei-Upload-Feld mit der Breite von 30 Zeichen erzeugt.
  • :maxlength
    Anzahl der Zeichen, die maximal eingegeben werden dürfen.
  • :accept
    Grenzt die zum Upload erlaubten Dateitypen ein, die als MIME-Typ übergeben werden können.
  • :class
    Angabe der CSS-Klasse, die zur Formatierung des Datei-Upload-Feldes genutzt werden soll.
  • :disabled
    Wenn true übergeben wird, wird das Datei-Upload-Feld deaktiviert.

Checkboxen

Wir hätten gerne in unserem Formular eine Checkbox, über die wir angeben können, ob der Mitarbeiter ein freier Mitarbeiter ist oder nicht.

Model erweitern

Damit wir diese Checkbox in unserem Formular anlegen können und die Werte aus der Checkbox auch in der Datenbank gespeichert werden, müssen wir unser Model Employee um ein Feld erweitern. Das neue Feld soll freelancer heißen und vom Datentyp boolean sein. Das heißt, wir legen folgende Migration an:

ruby script/generate migration AddFreelancerToEmployees \
     freelancer:boolean

Neu in Rails 2 ist, dass wir beim Anlegen einer Migration die Feldnamen und Typen der neuen Felder mit angeben können. Es wird folgende Migration-Datei erzeugt:

Listing  db/migrate/002_add_freelancer_to_employees.rb

class AddFreelancerToEmployees < ActiveRecord::Migration

  def self.up
    add_column :employees, :freelancer, :boolean
  end

  def self.down
    remove_column :employees, :freelancer
  end

end

Die Migration-Datei führen wir mit rake db:migrate aus, damit das neue Feld auch in der Datenbanktabelle employess angelegt wird.

Formular erweitern

Jetzt können wir unsere beiden Formulare zum Anlegen und Editieren von Mitarbeitern um eine Checkbox erweitern, über die wir angeben können, ob es sich bei dem jeweiligen Mitarbeiter um einen freien Mitarbeiter handelt oder nicht.

check_box

Zum Erzeugen einer Checkbox steht uns die Helper-Methode check_box zur Verfügung, die wir zunächst in das Formular zum Editieren eines Mitarbeiters einfügen:

Listing  app/views/employees/edit.html.erb

...
<p>
  <%= f.label :freelancer, "freier Mitarbeiter" %><br />
  <%=f.check_box :freelancer %>
</p>
...

Daraus wird folgender HTML-Code generiert:

<p>
  <label for="employee_freelancer">freier Mitarbeiter</label>
  <br />
  <input id="employee_freelancer" name="employee[freelancer]"
	 type="checkbox" value="1" />
  <input name="employee[freelancer]" type="hidden"
	 value="0" />
</p>

Verstecktes Feld

Da es sich bei einer Checkbox um ein Formularelement handelt, das, wenn es nicht gesetzt ist, keinen Wert überträgt, hat Rails automatisch ein verstecktes Feld angelegt, das genauso heißt wie die Checkbox und den Wert 0 hat. Dieser wird dann gesendet, wenn die Checkbox nicht gesetzt wird. Wird

die Checkbox gesetzt, wird der Wert 1 gesendet. Rails wandelt diese beiden Werte in die entsprechenden Boolean-Werte um, so dass in der Datenbank true oder false gespeichert wird.

Als HTML-Option können wir angeben, mit welcher CSS-Klasse wir die Checkbox formatieren möchten:

Listing  app/views/employees/edit.html.erb

...
<p>
  <%= f.label :freelancer, "freier Mitarbeiter" %><br />
  <%= f.check_box :freelancer, :class => "ja_nein" %>
</p>
...

Als zusätzliche Option können wir die Werte angeben, die übertragen werden sollen, wenn die Checkbox gesetzt bzw. nicht gesetzt ist:

Listing  app/views/employees/edit.html.erb

...
<p>
  <%= f.label :freelancer, "freier Mitarbeiter" %><br />
  <%= f.check_box :freelancer, {:class => "ja_nein"},
		  "Yes", "No" %>
</p>
...

Der Wert »Yes« würde übertragen, wenn die Checkbox gesetzt ist, und der Wert »No« würde über das versteckte Feld übertragen, wenn die Checkbox nicht gesetzt ist:

<p>
  <label for="employee_freelancer">freier Mitarbeiter</label>
  <br />
  <input class="ja_nein" id="employee_freelancer"
	 name="employee[freelancer]"
	 type="checkbox" value="Yes">
  <input name="employee[freelancer]"
	 type="hidden" value="No">
</p>

Da unser Feld freelancer aber vom Typ Boolean ist, ist das in diesem Fall nicht sinnvoll, da in der Datenbank die Werte true und false gespeichert werden müssen. Sinnvoll ist das für Felder, die vom Typ Text sind, weil dann die angegebenen Werte gespeichert werden können.

Radiobuttons

radio_button

Radiobuttons werden mit der Helper-Methode radio_button erzeugt, die als Parameter zum einen den Namen des Feldes im Model erwartet, das mit Hilfe der Radiobuttons gesetzt werden soll, und zum anderen der Wert, der übertragen werden soll. Da Rails in dem Fall nicht die Umwandlung von 1 und 0 in die entsprechenden Boolean-Werte übernimmt, müssen wir die Werte true und false übergeben:

Listing  app/views/employees/edit.html.erb

...
<p>
  <%= f.label :freelancer, "freier Mitarbeiter" %><br />
  Ja <%= f.radio_button :freelancer, true %>
  Nein <%= f.radio_button :freelancer, false %>
</p>
...

Es wird folgender HTML-Code erzeugt:

<p>
  <label for="employee_freelancer">freier Mitarbeiter</label>
  <br />
  Ja <input id="employee_freelancer_true"
	    name="employee[freelancer]"
	    type="radio" value="true" />
  Nein <input checked="checked"
	      id="employee_freelancer_false"
              name="employee[freelancer]" type="radio" />
</p>

Auswahllisten für Datumswerte

date_select

Beim Erzeugen der Ressource Employee mit dem scaffold -Generator haben wir für das Feld birthday den Datentyp date angegeben. Der Generator hat deshalb die Helper-Methode date_select gewählt, um die Eingabe des Geburtsdatums in den beiden Formularen zum Anlegen und Editieren von Mitarbeitern zu ermöglichen:

Listing  app/views/employees/edit.html.erb

...
<p>
  <%= f.label :birthday %><br />
  <%= f.date_select :birthday %>
</p>
...

Drei Auswahllisten

Die Methode date_select erzeugt drei Auswahllisten zur Eingabe von Tag, Monat und Jahr, die standardmäßig schon gesetzt werden. Die Jahreszahlen gehen 10 Jahre zurück:

<p>
  <label for="employee_birthday">Birthday</label><br />
    <select id="employee_birthday_1i"
	    name="employee[birthday(1i)]">
    <option value="1997">1997</option>
    <option value="1998">1998</option>
    ...
    <option value="2006">2006</option>
    <option value="2007">2007</option>
  </select>

  <select id="employee_birthday_2i"
  	  name="employee[birthday(2i)]">
    <option value="1">January</option>
    <option value="2">February</option>
    ...
    <option value="11">November</option>
    <option value="12">December</option>
  </select>

  <select id="employee_birthday_3i"
	  name="employee[birthday(3i)]">
    <option value="1">1</option>
    <option value="2">2</option>
    ...
    <option value="30">30</option>
    <option value="31">31</option>
  </select>
</p>

Optionen

Mit Hilfe von Optionen können Sie Einfluss auf die Werte und Anzeigeart der Auswahllisten nehmen.

  • :start_year
    Startwert für die Liste zur Auswahl des Jahres
  • :end_year
    Endwert für die Liste zur Auswahl des Jahres
  • :order
    Gibt die Reihenfolge an, in der die Listfelder angezeigt werden sollen, zum Beispiel :order => [:day, :month, :year] . Lässt man in dem Array einen Wert weg, wird die entsprechende Liste nicht angezeigt.
  • :use_month_numbers
    Bei Übergabe von true werden nicht mehr die Monatsnamen, sondern die Zahlen 1--12 in der Liste zur Auswahl des Monats angezeigt.
  • :discard_day
    Bei Übergabe von true wird die Liste zur Auswahl des Tages nicht angezeigt.
  • :discard_month
    Bei Übergabe von true werden die Listen zur Auswahl des Monats und des Tages nicht angezeigt.
  • :discard_year
    Bei Übergabe von true wird die Liste zur Auswahl des Jahres nicht angezeigt.
  • :default
    Legt das Default-Datum fest. Kann als Hash-Wert übergeben werden, zum Beispiel :default => {:day => 24, :month => 12, :year => 1980\ } oder durch Anwendung einer ActiveSupport-Helper-Methode für Datum und Zeit wie zum Beispiel :default => 3.days.from_now .
  • :include_blank
    Bei Übergabe von true wird als erster Eintrag in der Liste ein leerer Eintrag angelegt. Dadurch wird ermöglicht, kein Datum zu wählen.

Beispiel

Die Anwendung einiger dieser Optionen am Beispiel der Eingabefelder für das Geburtsdatum in dem Formular zum Editieren eines Mitarbeiters:

Listing  app/views/employees/edit.html.erb

...
<p>
  <%= f.label :birthday %><br />
  <%= f.date_select :birthday,
		    :start_year => 1970,
		    :end_year => 2009,
		    :order => [:day, :month, :year],
		    :use_month_numbers => true,
		    :include_blank => true %>
</p>
...

Auswahllisten für Zeitwerte

time_select

Um Auswahllisten zur Auswahl von Uhrzeiten zu erzeugen, stellt Rails die Helper-Methode time_select zur Verfügung. Der Helper generiert Auswahllisten für Stunden, Minuten und optional auch von Sekunden.

Neu in Rails 2 ist die Möglichkeit, mit der Option minute_step für die Minuten-Auswahlliste die Intervalle festzulegen. f.time_select :zeit, :minute_step => 15 generiert z. B. neben der Stunden-Auswahlliste eine Minuten-Auswahlliste mit den Werten 00, 15, 30 und 45 Minuten.

Optionen

Folgende Optionen stehen für time_select zur Verfügung:

  • :include_seconds
    Zusätzlich zur Auswahlliste für Stunden und Minuten wird auch eine Auswahlliste für Sekunden generiert.
  • :minute_step
    Hiermit wird das Intervall für die Minuten festgelegt.

Auswahllisten für Zeit- und Datumswerte

datetime_select

Um Auswahllisten zur Auswahl von Datums- und Zeitwerten zu erzeugen, können Sie die Helper-Methode datetime_select verwenden. Es stehen im Wesentlichen die gleichen Optionen wie bei date_select und time_select zur Verfügung.

Länderauswahllisten

Es soll möglich sein, über unsere Formulare zum Anlegen oder Editieren eines Mitarbeiters anzugeben, aus welchem Land der Mitarbeiter kommt. Dazu benötigen wir ein neues Feld country in unserem Model, das wir mit einer neuen Migration anlegen:

ruby script/generate migration AddCountryToEmployees \
     country:string
rake db:migrate

country_select

Die Auswahlliste zur Auswahl des Landes fügen wir zunächst in unser Formular zum Editieren eines Mitarbeiters ein. Dazu nutzen wir die Helper-Methode country_select:

Listing  app/views/employees/edit.html.erb

<p>
  <%= f.label :country, "Land" %><br />
  <%= f.country_select :country %>
</p>

Auswal erleichtern

Es wird eine Auswahlliste generiert, das alle Länder enthält. Bei einer solch langen Liste ist es schwierig, den richtigen Eintrag auszuwählen. Da die meisten Besucher einer Website immer aus dem gleichen Land oder den Nachbarländern des Webseitenbetreibers kommen, kann man die Liste komfortabler gestalten, indem man eine bestimmte Auswahl von Ländern an den Anfang der Liste stellt. Dazu übergibt man die jeweiligen Länder in einem Array als zweiten Parameter an die Methode country_select:

Listing  app/views/employees/edit.html.erb

<p>
  <%= f.label :country, "Land" %><br />
  <%= f.country_select :country,
       %w(Germany Luxembourg France Belgium Netherlands)
  %>
</p>

Daraus wird folgender HTML-Code generiert:

...
<p>
<label for="employee_country">Land</label><br />
<select id="employee_country" name="employee[country]">
<option value="Germany">Germany</option>
<option value="Luxembourg">Luxembourg</option>
<option value="France">France</option>
<option value="Belgium">Belgium</option>
<option value="Netherlands">Netherlands</option>
<option value="">-------------</option>
<option value="Afghanistan">Afghanistan</option>
<option value="Albania">Albania</option>
...
<option value="Zambia">Zambia</option>
<option value="Zimbabwe">Zimbabwe</option>
</select>
</p>
...

include_blank

Wenn es sich bei dem Feld zur Auswahl des Landes um ein optionales Feld handelt, das nicht zwingend gesetzt werden muss, steht Ihnen auch hier die Option :include_blank => true zur Verfügung, die als ersten Eintrag in der Liste einen leeren Eintrag erzeugt, damit es immer möglich ist, nichts auszuwählen:

Listing  app/views/employees/edit.html.erb

...
<p>
  <%= f.label :country, "Land" %><br />
  <%= f.country_select :country,
       %w(Germany Luxembourg France Belgium Netherlands),
       :include_blank => true
  %>
</p>
...

Wenn Sie möchten, dass in der Auswahlliste eine Aufforderung zur Auswahl wie »Bitte wählen« angezeigt wird, steht Ihnen die Option :prompt zur Verfügung:

Listing  app/views/employees/edit.html.erb

...
<p>
  <%= f.label :country, "Land" %><br />
  <%= f.country_select :country,
       %w(Germany Luxembourg France Belgium Netherlands),
       :include_blank => true,
       :prompt => "Bitte wählen"
  %>
</p>
...

:prompt

Wenn Sie der Option :prompt den Wert true übergeben, generiert sie als ersten Eintrag in der Liste »Please select«, und wenn Sie eine Zeichenkette übergeben einen Eintrag mit dieser Zeichenkette. Und zwar immer dann, wenn für den betreffenden Datensatz noch kein Land gespeichert wurde. Also im Formular zum Anlegen eines Mitarbeiters immer und im Formular zum Editieren eines Mitarbeiters immer dann, wenn für diesen Mitarbeiter noch kein Land ausgewählt wurde. Sobald ein Land für den Mitarbeiter ausgewählt und der Datensatz gespeichert wird, ist der Eintrag beim nächsten Editieren nicht mehr vorhanden.

Im Gegensatz dazu generiert die Option include_blank => true immer einen leeren Eintrag in der Liste.

Die Ländernamen werden in unserem Listfeld auf Englisch angezeigt. Auch die Monatsnamen würden auf Englisch ausgegeben, wenn wir der Methode date_select nicht die Option :use_month_numbers => true übergeben würden. Wenn wir das nicht möchten, können wir das Globalite-Plug-in nutzen, mit dessen Hilfe die Listeneinträge automatisch lokalisiert werden.

Mehr zum Einsatz des Globalite-Plugins erfahren Sie im Abschnitt 15.2.2.

Listfelder mit statischen Werten

Wir möchten gerne Anrede und Titel zu einem Mitarbeiter in unserer Beispiel-Applikation speichern können. Die möglichen Werte, wie zum Beispiel »Frau Dr.«, sollen über ein Auswahlliste auswählbar sein, und sie sollen als Zeichenkette in der Datenbank gespeichert werden.

Model erweitern

Deshalb müssen wir zuerst das dafür erforderliche Feld in der Datenbank anlegen:

ruby script/generate migration AddTitleToEmployees \
     title:string
rake db:migrate

select

Zur Erzeugung der Auswahlliste innerhalb unserer Formulare zum Anlegen und Editieren eines Mitarbeiters stellt uns Rails die Helper-Methode select zur Verfügung. Die einzelnen Werte, die wir innerhalb des Listfeldes anzeigen möchten, übergeben wir als Array an diese Methode:

Listing  app/views/employees/edit.html.erb

...
<p>
  <%= f.label :title, "Anrede" %><br />
  <%= f.select :title,
       ["Frau", "Frau Dr.", "Herr", "Herr Dr."] %>
</p>
...

Optionen

Folgende Optionen stehen Ihnen zur Verfügung:

  • :include_blank
    Bei Übergabe von true wird als erster Eintrag in der Liste ein leerer Eintrag angelegt. Dadurch wird ermöglicht, keinen Wert zu wählen.
  • :prompt
    Bei Übergabe von true wird als erster Eintrag »Please select« erzeugt, bei Übergabe einer Zeichenkette ein Eintrag mit dieser Zeichenkette. Sobald ein Wert ausgewählt und für das Objekt gespeichert wurde, erzeugt :prompt bei den nächsten Aufrufen des Formulars keine Ausgabe mehr.

Am Beispiel unseres Formulars zum Editieren eines Mitarbeiters könnte der Einsatz dieser HTML-Optionen wie folgt aussehen:

Listing  app/views/employees/edit.html.erb

...
<p>
  <%= f.label :title, "Anrede" %><br />
  <%= f.select :title,
		["Frau", "Frau Dr.", "Herr", "Herr Dr."],
		:include_blank => true,
		:prompt => "Bitte wählen"
  %>
</p>
...

Konstante definieren

Das Array mit den Werten in der Template-Datei anzugeben, ist nicht praktikabel. Wenn zum Beispiel die Auswahlliste an mehreren Stellen eingesetzt werden soll, müsste es in mehreren Template-Dateien eingesetzt werden, und wenn dann die Einträge bearbeitet werden sollen, müssten sie in allen Template-Dateien bearbeitet werden. Deshalb definieren wir im Model Employee eine Konstante, die das Array enthält:

Listing  app/models/employee.rb

class Employee < ActiveRecord::Base#
  TITLES = ["Frau", "Frau Dr.", "Herr", "Herr Dr."];
end

Diese Konstante rufen wir dann in unserem Formular zum Editieren eines Mitarbeiters auf, um die Werte für Anrede und Titel an die Auswahlliste zu übergeben:

Listing  app/views/employees/edit.html.erb

...
<p>
  <%= f.label :title, "Anrede" %><br />
  <%= f.select :title,
	       Employee::TITLES ,
	       :include_blank => true,
	       :prompt => "Bitte wählen"
  %>
</p>
...

Es wird folgender HTML-Code generiert:

...
<p>
<label for="employee_title">Anrede</label><br />
<select id="employee_title" name="employee[title]">
  <option value=''>Bitte wählen</option>
  <option value=''></option>
  <option value='Frau'>Frau</option>
  <option value='Frau Dr.'>Frau Dr.</option>
  <option value='Herr'>Herr</option>
  <option value='Herr Dr.'>Herr Dr.</option>
</select>
</p>
...

Alternative

Alternativ können Sie auch ein zweidimensionales Array angeben:

Listing  app/models/employee.rb

class Employee < ActiveRecord::Base#
  TITLES = [["Frau", "f"], ["Frau Dr.", "f-dr"],
	    ["Herr", "m"], ["Herr Dr.", "m-dr"]];
end

Der select -Helper generiert dann folgender HTML-Code:

...
<p>
<label for="employee_title">Anrede</label><br />
<select id="employee_title" name="employee[title]">
  <option value=''>Bitte wählen</option>
  <option value=''></option>
  <option value='f'>Frau</option>
  <option value='f-dr'>Frau Dr.</option>
  <option value='m'>Herr</option>
  <option value='m-dr'>Herr Dr.</option>
</select>
</p>
...

Listfelder mit dynamischen Werten

Es soll möglich sein, in den Formularen unserer Beispiel-Applikation zum Anlegen und Editieren eines Mitarbeiters aus einer Auswahlliste auszuwählen, in welcher Abteilung der jeweilige Mitarbeiter arbeitet.

Die Werte innerhalb dieser Auswahlliste sollen nicht, wie in der Auswahlliste zur Auswahl von Anrede und Titel über eine Konstante definiert, sondern in einem eigenen Model gespeichert werden. Das hat den Vorteil, dass die Werte einfacher gepflegt werden können.

Ressource erzeugen

Wir möchten zunächst nur den Namen der Abteilungen in dem Model speichern. Also erzeugen wir die Ressource Department mit dem Feld name:

ruby script/generate scaffold department name:string

rake db:migrate

Wenn Sie jetzt den lokalen Rails-Server starten, können Sie durch Aufruf der URL http://localhost:3000/departments die Ressource testen und über den Link New department neue Abteilungen wie zum Beispiel Verwaltung, Development und Bodenpersonal anlegen.

Abbildung  http://localhost:3000/departments

Beziehungen

Die Abteilungen, die wir angelegt haben, sollen in einer Auswahlliste in unseren Fomularen zum Anlegen und Editieren eines Mitarbeiters angezeigt werden, und der jeweils ausgewählte Wert soll zu den Mitarbeitern im Model Employee gespeichert werden. Die Beziehung zwischen den beiden Models Employee und Department ist wie folgt definiert:

Zu einem Department gehören beliebig viele Employees, und ein Employee gehört zu genau einem Department:

Abbildung  Beziehung zwischen Employee und Department

Das heißt, dass wir im Model Employee den Eintrag belongs_to :department hinzufügen müssen und im Model Department den Eintrag has_many :employees:

Listing  app/models/employee.rb

class Employee < ActiveRecord::Base#
  belongs_to :department
  ...
end

Listing  app/models/department.rb

class Department < ActiveRecord::Base
  has_many :employees
end

Model erweitern

Damit diese Beziehung zwischen Employee und Department auch wirklich funktioniert, müssen wir im Model Employee die Abteilung, zu der der Mitarbeiter gehört, speichern. Dazu benötigen wir ein zusätzliches Feld department_id in der Datenbank, in dem die ID der jeweiligen Abteilung gespeichert werden kann:

ruby script/generate migration AddDepartmentIdToEmployees \
     department_id:integer
rake db:migrate

Formulare erweitern

In den Formularen zum Anlegen und Editieren eines Mitarbeiters müssen wir jetzt die Auswahlliste zur Auswahl der Abteilung hinzufügen:

Listing  app/views/employees/edit.html.erb

...
<p>
  <%= f.label :department_id, "Abteilung" %><br />
  <%= f.select :department_id,
       Department.find(:all).collect{|d| [d.name,d.id]} %>
</p>
...

Die Werte für die Auswahlliste werden aus der Datenbank ausgelesen und als zweidimensionales Feld mit dem Namen und der ID der jeweiligen Abteilung übergeben.

Daraus wird folgender HTML-Code generiert:

<p>
<label for="employee_department_id">Abteilung</label><br />

<select id="employee_department_id" name="employee[department_id]">
<option value='1'>Verwaltung</option>
<option value='2'>Development</option>
<option value='3'>Bodenpersonal</option>
</select>
</p>

Um auch in dieser Auswahlliste als ersten Eintrag »Bitte wählen« anzuzeigen, fügen wir noch die HMTL-Option :prompt => "Bitte wählen" hinzu:

Listing  app/views/employees/edit.html.erb

...
<p>
<%= f.label :department_id, "Abteilung" %><br />
<%= f.select :department_id,
	     Department.find(:all).collect{|d| [d.name,d.id]},
	     :prompt => "Bitte wählen" %>
</p>
...

Aufgabe des Controllers

Wir haben in der Template-Datei die Werte aus der Datenbank mit der find -Methode abgefragt. Da das nicht die Aufgabe des Views, sondern des Controllers ist, lagern wir das Auslesen der Werte in den Employees-Controller aus. Und zwar in die beiden Actions new und edit, da wir die Liste sowohl im Formular zum Anlegen eines Mitarbeiters als auch zum Editieren eines Mitarbeiters anzeigen möchten:

Listing  app/controllers/employees_controller.rb

...
def new
   @employee = Employee.new
   @departments = Department.find(:all)
   ...
end

def edit
   @employee = Employee.find(params[:id])
   @departments = Department.find(:all)
end
...

In der Template-Datei wird dann auf die Instanzvariable @departments zugegriffen:

Listing  app/views/employees/edit.html.erb

...
<p>
<%= f.label :department_id, "Abteilung" %><br />
<%= f.select :department_id,
	    @departments .collect {|d| [d.name,d.id]},
	    :prompt => "Bitte wählen" %>
</p>
...

collection_select

Damit wir auch den Aufruf der Methode collect zur Generierung des zweidimensionalen Feldes nicht mehr in der Template-Datei haben, können wir die Helper-Methode collection_select einsetzen, um die Auswahlliste zu erzeugen:

Listing  app/views/employees/edit.html.erb

...
<p>
<%= f.label :department_id, "Abteilung" %><br />
<%= f.collection_select :department_id,
			@departments, :id, :name,
			:prompt => "Bitte wählen" %>
</p>
...

Die Methode collection_select erwartet als Parameter neben dem Namen des Feldes department_id ein Array von Objekten (Collections), die die Werte aus der Datenbank enthält (@departments), den Namen des Feldes aus der Datenbank, dessen Wert im Formular übertragen werden soll (id), und den Namen des Feldes aus der Datenbank, dessen Wert in der Auswahlliste angezeigt werden soll (name). Achten Sie bitte auf die Reihenfolge!


Rheinwerk Computing - Zum Seitenanfang

Validierung  Zur nächsten ÜberschriftZur vorigen Überschrift

Die Validierung ist ein sehr wichtiges Thema, wenn es um Formulare geht. Bestimmte Felder dürfen nicht vom User leer gelassen werden und manchmal muss der Inhalt einem bestimmten Format entsprechen, wie zum Beispiel die Angabe der E-Mail-Adresse. Im Abschnitt 10.11 stellen wir Ihnen alle Validierungsregeln ausführlich vor. Im Rahmen dieses Kapitels, möchten wir uns auf die Validierungsregeln, die den View betreffen, beschränken.

In unseren Formularen zum Anlegen und Editieren eines Mitarbeiters soll zum Beispiel die Angabe des Nachnamens eine Pflichtangabe sein. Das Feld darf also nicht leer gelassen werden.

Helper

Rails unterstützt uns auch bei der Validierung von Formularen mit einer Reihe von Helper-Methoden. Die »Prüfung«, ob ein Feld ausgefüllt wurde, erfolgt im Model mit Hilfe der Methode validates_presence_of, der wir den Feldnamen des Feldes, das geprüft werden soll, übergeben. In unserem Fall prüfen wir das Feld lastname im Model Employee:

Listing  app/models/employee.rb

class Employee < ActiveRecord::Base#
  belongs_to :department

  validates_presence_of :lastname

...
end

Wenn Sie jetzt den lokalen Rails-Server neu starten und das Formular zum Editieren eines Mitarbeiters ohne Angabe eines Mitarbeiters aufrufen, erhalten Sie folgende Fehlermeldung:

Abbildung  Fehlermeldung

create und update erweitern

Das Formular zum Editieren eines Mitarbeiters wird an die Action update im Employees-Controller geschickt. Falls das ein Pflichtfeld nicht ausgefüllt wurde, muss wieder das Formular zum Editieren angezeigt werden. Das Formular greift auf die Instanzvariable @departments zu, die aber nicht von der Action update gesetzt wurde. Gleiches gilt für die Action create, an die das Formular zum Anlegen eines Mitarbeiters gesendet wird. Das heißt, wir müssen auch in den Actions create und update die Instanzvariable @departments setzen:

Listing  app/controllers/employees_controller.rb

...
def create
  @employee = Employee.new(params[:employee])

  respond_to do |format|
    if @employee.save
      flash[:notice] = 'Employee was successfully created.'
      format.html { redirect_to(@employee) }
      format.xml  { render :xml => @employee,
        :status => :created, :location => @employee }
    else
      @departments = Department.find(:all)
      format.html { render :action => "new" }
      format.xml  { render :xml => @employee.errors,
      :status => :unprocessable_entity }
    end
  end
end

def update
  @employee = Employee.find(params[:id])

  respond_to do |format|
    if @employee.update_attributes(params[:employee])
      flash[:notice] = 'Employee was successfully updated.'
      format.html { redirect_to(@employee) }
      format.xml  { head :ok }
    else
      @departments = Department.find(:all)
      format.html { render :action => "edit" }
      format.xml  { render :xml => @employee.errors,
      :status => :unprocessable_entity }
    end
  end
end
...

Fehlermeldung

Wenn wir jetzt wieder das Formular zum Editieren eines Mitarbeiters ohne Angabe eines Nachnamens abschicken, erhalten wir folgende Ausgabe:

Abbildung  Nachname muss angegeben werden

Fehlermeldung ausgeben

Es wird oberhalb des Formulars ein rot umrandeter Kasten mit einer Fehlermeldung angezeigt, und das Feld »Nachname« wird mit einem roten Kasten umgeben.

Die Fehlermeldung oberhalb des Formulars wird ausgegeben, weil der Generator beim Erstellen der Resource employee folgende Helper-Methode oberhalb der Formulare zum Anlegen und Editieren eines Mitarbeiters eingefügt hat:

Listing  app/views/employees/edit.html.erb

<%= error_messages_for :employee %>

Da die Ausgabe auf Englisch erfolgt, ist diese Helper-Methode für uns ungeeignet, wenn wir eine deutschsprachige Applikation entwickeln. Sie können durch Einsatz des Globalite-Plug-ins den Fehlertext zwar in eine andere Sprache übersetzen lassen, aber da innerhalb der Fehlermeldung der Name des Models und der Name der betroffenen Felder ausgegeben werden und diese auch auf Englisch sind, wäre das nur für den Adminbereich einer Applikation akzeptabel. Den Usern Ihrer Web-Applikationen können Sie das nicht zumuten.

Das heißt, wir setzen die Helper-Methode error_messages_for nicht ein und löschen den entsprechenden Einträge aus den Template-Dateien.

Wenn wir jetzt wieder das Formular zum Editieren eines Mitarbeiters ohne Angabe eines Nachnamens aufrufen, erhalten wir folgende Ausgabe:

Abbildung  Die Fehlermeldung wird nicht angezeigt

Die Fehlermeldung oberhalb des Formulars wird nun nicht mehr ausgegeben, aber das Feld »Nachname« wird nach wie vor rot markiert. Im HTML-Code sieht man, dass sowohl das Label als auch das Textfeld zur Eingabe des Nachnamens von einem Bereich umgeben werden, der mit der CSS-Klasse fieldWithErrors formatiert wird:

...
<p>
  <div class="fieldWithErrors">
    <label for="employee_lastname">Nachname</label>
  </div>
  <br />
  <div class="fieldWithErrors">
    <input id="employee_lastname" name="employee[lastname]"
	   size="20" type="text" value="" /></div>
</p>
...

scaffold.css

Die beiden div -Tags mit Angabe der CSS-Klasse wurden automatisch von Rails erstellt. Beim Generieren der Ressource employee wurde auch die CSS-Datei scaffold.css im Verzeichnis public/stylesheets angelegt. In dieser Datei ist die CSS-Klasse fieldWithErrors definiert. Diese können Sie anpassen oder überschreiben.

Fehlermeldung zum Feld ausgeben

Wir möchten gerne, dass ein Fehlertext unterhalb des Feldes zur Eingabe des Nachnamens ausgegeben wird, wenn das Feld nicht ausgefüllt wurde. Dazu stellt uns Rails die Helper-Methode error_message_on zur Verfügung, die wir auf die einzelnen Formularfelder anwenden können:

Listing  app/views/employees/edit.html.erb

...
<p>
  <%= f.label :lastname, "Nachname" %><br />
  <%= f.text_field :lastname, :size => 20 %>
  <%= f.error_message_on :lastname %>
</p>
...

Jetzt wird beim Absenden des Formulars zum Editieren eines Mitarbeiters ohne Angabe eines Nachnamens Folgendes ausgegeben:

Abbildung  Fehlermeldung unterhalb des Feldes

Standard-Fehlermeldung

Die Fehlermeldung »can't be blank« ist die Standardfehlermeldung, die Rails für diesen Fall ausgibt. Wenn Sie das Globalite-Plug-in installiert haben, wird »muss ausgefüllt werden« für die deutsche Übersetzung ausgegeben. Wenn Sie einen eigenen Fehlertext angeben möchten, können Sie diesen im Model mit Hilfe des Parameters :message der Methode validates_presence_of übergeben:

Listing  app/models/employee.rb

validates_presence_of :lastname, :message=>"Bitte ausfüllen"

Jetzt wird statt der Standardfehlermeldung die Fehlermeldung »Bitte ausfüllen« ausgegeben, wenn das Feld »Nachname« nicht ausgefüllt wird.

Das heißt, auch die Validierung ist bei Formularen mit Bezug zu einem Model ganz einfach. Rails stellt uns genügend Helper-Methoden zur Verfügung, mit deren Hilfe wir im Model definieren können, wann ein Feld gültig ist. In Kapitel 10 stellen wir Ihnen alle Helper-Methoden, die zur Validierung zur Verfügung stehen, ausführlich vor.

In einer Template-Datei können wir mit der Methode error_message_for alle Fehlermeldungen zusammen ausgeben oder mit Hilfe der Methode error_message_on zu genau einem Feld eine Fehlermeldung ausgeben; welche, können wir im Model definieren.

Wie ein Feld, das fehlerhaft oder gar nicht ausgefüllt wurde, dargestellt werden soll, können wir mit Hilfe der CSS-Klasse fieldWithErrors definieren.

Bis hierhin haben wir Ihnen die Erzeugung und Verwendung der meistverwendeten Felder für Formulare mit Bezug zu einem Model vorgestellt. Der Vorteil dieser Formulare liegt vor allem darin, dass die Werte (value -Attribute) der einzelnen Formularfelder automatisch mit den entsprechenden Objekt-Attributen gesetzt werden.


Rheinwerk Computing - Zum Seitenanfang

Formulare mit Bezug zu mehr als einem Model  Zur nächsten ÜberschriftZur vorigen Überschrift

fields_for

Die Helper-Methode form_for erlaubt uns nur ein Model-Objekt zu übergeben, wie z. B. form_for(@employee) . Was ist aber, wenn wir mehr als ein Objekt gleichzeitig in einem Formular verarbeiten möchten? Angenommen, Sie möchten nicht nur die Informationen zu einem Mitarbeiter, sondern gleichzeitig auch die Informationen der Abteilung (Department) in einem Formular bearbeiten können. In diesem Fall kommt die Helper-Methode fields_for zum Einsatz.

Das Formular sieht dann wie folgt aus:

Listing  app/views/employee/_form.html.erb

<% form_for(@employee) do |f| %>
  <p>
    <%= f.label :title,"Anrede" %><br />
    <%= f.select :title, Employee::TITLES,
		 :prompt => "Bitte wählen" %>
  </p>
  <p>
    <%= f.label :fristname,"Vorname" %><br />
    <%= f.text_field :firstname %>
  </p>
  ...
  <% fields_for( @employee.department) do |department_f| %>
    <p>
      <%= department_f.label :name,"Abteilungsname" %><br />
      <%= department_f.text_field :name %>
    </p>
  <% end %>
  <p>
    <%= f.submit "Update" %>
  </p>
<% end %>
Der Bereich fields_for(...) sieht so aus, als ob es sich um eine Art Unterformular handeln würde. In Wirklichkeit wird der Bereich
<% fields_for( @employee.department) do |department_f| %>
  <p>
    <%= department_f.label :name,"Abteilungsname" %><br />
    <%= department_f.text_field :name %>
  </p>
<% end %>
wie folgt in HTML umgesetzt:
<p>
  <label for="department_name">Abteilungsname</label><br />
  <input id="department_name" name="department[name]"
   size="30" type="text" value="Verwaltung" />
</p>

Zugriff im Controller

Im Controller kann man dann mit dem Befehl params[:department] auf die Formulardaten zugreifen. Damit die Formulardaten des Department gespeichert werden können, müssen wir die Action update um den Aufruf
@employee.department.update_attributes(params[:department])
wie folgt ergänzen:

Listing  /app/controllers/employees_controller.rb

def update
  @employee = Employee.find(params[:id])

  respond_to do |format|
    if @employee.update_attributes(params[:employee]) &&
       @employee.department.update_attributes(
         params[:department])
         flash[:notice] = 'Employee was successfully updated.'
         format.html { redirect_to(@employee) }
         format.xml { head :ok }
         ...
    end
  end
end

Rheinwerk Computing - Zum Seitenanfang

Formulare ohne Bezug zu einem Model  Zur nächsten Überschrifttop

Formulare ohne Bezug zu einem Model begegnen uns seltener. Wir benötigen sie zum Beispiel für Suchformulare. Die Eingaben in solche Formulare dienen nicht dazu, in einem Model gespeichert zu werden. Wir möchten Ihnen Formulare ohne Bezug zu einem Model an einem einfachen Beispielformular zeigen, in das man einen Wert in ein Textfeld eingeben kann, der nach dem Absenden des Formulars wieder ausgegeben wird. Wir generieren zunächst in unserer Beispiel-Applikation employees einen neuen Controller formdemo mit den beiden Actions input und output :
ruby script/generate controller formdemo input output

form_tag

Das Formular werden wir in dem Template input.html.erb im Verzeichnis app/views/formdemo anlegen. Auch für Formulare ohne Bezug zu einem Model stehen ActionView-Helper-Methoden zur Verfügung, die den Namen des Feldes und Attribute, wie der Value oder die Größe des Feldes, als Parameter erwarten. Jede dieser Helpermethoden endet mit _tag . Ein Formular wird mit der Methode form_tag generiert, die als Parameter die Action des Controllers, an die die Werte aus dem Formular zur Verarbeitung geschickt werden sollen, und einen Block, innerhalb dem die einzelnen Formularelemente generiert werden, erwartet:

Listing  app/views/formdemo/input.html.erb

<h2>Fomdemo</h2>
<% form_tag :action => "output" do %>
<p>
<%= label :example_text, "Beispiel Textfeld" %>
<%= text_field_tag :example_text, "default Wert" %>
</p>
<%= submit_tag "go" %>
<% end %>

Formularfelder

Über den Parameter :action geben wir an, dass die Action output die Formularwerte verarbeitet. Zur Erzeugung eines Textfeldes steht uns die Helper-Methode text_field_tag zur Verfügung, der wir einen Standardwert, mit dem das Feld vorbelegt werden soll, übergeben können.

label

Zur Beschriftung eines Feldes nutzen wir die Methode label, die als Parameter den Namen des Feldes, zu dessen Beschriftung das Label dienen soll, und die Beschriftung selbst erwartet.

submit_tag

Zur Generierung des Absendebuttons steht uns die Methode submit_tag zur Verfügung, die als Parameter die Beschriftung des Buttons erwartet.

Wenn Sie den lokalen Rails-Server starten und das Formular aufrufen, ausfüllen und absenden, erhalten Sie folgende Ausgabe:

Abbildung  http://localhost:3000/formdemo/output

Formularwerte verarbeiten

Da wir in der Methode form_tag angegeben haben, dass die Formularwerte von der Action output im Formdemo-Controller verarbeitet werden sollen, die Action aber noch leer ist, also die Formularwerte noch gar nicht verarbeitet, wird nur die Template-Datei output.hrml.erb aufgerufen. Das heißt, wir müssen in der Action output die Formularwerte verarbeiten und sie dem Template in einer Instanzvariablen zur Verfügung stellen, damit sie im Template angezeigt werden können.

Alle Werte eines Formulars werden über den Hash params übertragen. Das heißt, wir können die einzelnen Werte im Controller aus diesem Hash auslesen:

Listing  app/controllers/formdemo_controller.erb

class FormdemoController < ApplicationController

  def input
    # Anzeige des Formulars
  end

  def output
    @example_text = params[:example_text]
  end
end

Die Instanzvariable @example_text können wir in der Template-Datei output.html.erb verwenden:

Listing  app/views/formdemo/output.html.erb

<h2>Fomdemo: output</h2>

<p>
Beispieltext: <%= @example_text %>
</p>

Wenn Sie das Formular erneut aufrufen, ausfüllen und absenden, wird der von Ihnen eingegebene Text ausgegeben.

Im Prinzip stehen für Formulare ohne Bezug zu einem Model Helper-Methoden für die gleichen Formularfelder wie für Formulare mit Bezug zu einem Model zur Verfügung. Der Unterschied besteht darin, dass jede dieser Helper-Methoden mit _tag endet. Beispiele wären die Methoden text_area_tag, um mehrzeilige Textfelder zu erzeugen, password_field_tag, um Passwort-Eingabefelder zu erzeugen, und die Methode check_box_tag, um Checkboxen zu erzeugen.-->



Ihre Meinung

Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.

 <<   zurück
  Zum Rheinwerk-Shop
Zum Rheinwerk-Shop: Ruby on Rails 2
Ruby on Rails 2
Jetzt Buch bestellen
 Ihre Meinung?
Wie hat Ihnen das Openbook gefallen?
Ihre Meinung

 Buchtipps
Zum Rheinwerk-Shop: Ruby on Rails 3.1






 Ruby on Rails 3.1


Zum Rheinwerk-Shop: Responsive Webdesign






 Responsive Webdesign


Zum Rheinwerk-Shop: Suchmaschinen-Optimierung






 Suchmaschinen-
 Optimierung


Zum Rheinwerk-Shop: JavaScript






 JavaScript


Zum Rheinwerk-Shop: Schrödinger lernt HTML5, CSS3 und JavaScript






 Schrödinger lernt
 HTML5, CSS3
 und JavaScript


 Lieferung
Versandkostenfrei bestellen in Deutschland, Österreich und der Schweiz
InfoInfo




Copyright © Rheinwerk Verlag GmbH 2008
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das Openbook denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt.
Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


Nutzungsbestimmungen | Datenschutz | Impressum

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de

Cookie-Einstellungen ändern