8.5 Formulare
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
Formulare mit Bezug zu einem Model
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:
Zum Anlegen eines Mitarbeiters in unserer Beispiel-Applikation wird folgender HTML-Code generiert:
<% form_for :employee, @employee, :url => employee_path, :html => { :class => "new_employee", :id => "new_employee" } do |f| %> ... <% end %>
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:
Zum Editieren eines Mitarbeiters in unserer Beispiel-Applikation wird folgender HTML-Code generiert:
<% form_for :employee, @employee, :url => employee_path(@employee), :html => { :method => :put, :class => "edit_employee", :id => "edit_employee_1" } do |f| %> ... <% end %>
<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!
Validierung
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.
Formulare mit Bezug zu mehr als einem Model
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 %>
<% fields_for( @employee.department) do |department_f| %> <p> <%= department_f.label :name,"Abteilungsname" %><br /> <%= department_f.text_field :name %> </p> <% end %>
<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])
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
Formulare ohne Bezug zu einem Model
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.