9.2 Aufgaben des Controllers 

Die Klasse ActionController stellt zur Bewältigung der Aufgaben eines Controllers eine Reihe von Methoden zur Verfügung. Die wichtigsten dieser Methoden werden wir Ihnen in den folgenden Abschnitten zeigen.
Daten aus HTTP-Anfragen empfangen 

params
Auf Daten, die über die HTTP-Methoden GET, POST, PUT und DELETE gesendet werden, kann im Controller über die Methode params[] zugegriffen werden:
# Aufruf einer URL mit GET-Methode
http://localhost:3000/countries?page=3&num=10
# Auslesen des Parameters :page im Controller
params[:page]
=> 3
# Auslesen des Parameters :num im Controller
params[:num]
=> 10
params ist kein Hash |
Der Zugriff auf die Methode params erfolgt wie der Zugriff auf einen Hash,
was auch beabsichtigt ist, aber genau genommen ist [] eine Methode des
Objekts params.
Im folgenden Beispiel wird eine Klasse mit der Methode, die den Namen []
trägt, definiert:
class Frage |
request
Mit Hilfe der Methode request haben Sie Zugriff auf alle Informationen, die Rails über die aktuelle Anfrage vorliegen. Dazu zählen unter anderem:
- request.remote_ip
Gibt die IP-Adresse des Clients zurück.
- request.method
Gibt die Art der Anfrage ( :get , :post , :put oder :delete ) zurück.
- request.get?
Liefert true zurück, wenn die Anfrage mit der HTTP-Methode GET gesendet wurde.
- request.post?
Liefert true zurück, wenn die Anfrage mit der HTTP-Methode POST gesendet wurde.
- request.put?
Liefert true zurück, wenn die Anfrage mit der HTTP-Methode PUT gesendet wurde.
- request.delete?
Liefert true zurück, wenn die Anfrage mit der HTTP-Methode DELETE gesendet wurde.
- request.xml_http_request?
Liefert true zurück, wenn es sich um eine Ajax-Anfrage handelt. Als Abkürzung kann auch request.xhr? verwendet werden.
- request.domain
Gibt die angefragte Domain zurück.
- request.env
Mit der Methode request.env ist es möglich, auf die Umgebungsvariablen, die u. a. vom Apache-Webserver gesetzt werden, zuzugreifen. Zum Beispiel request.env["HTTP_USER_AGENT"] , um den anfragenden Browser abzufragen, oder request.env["HTTP_ACCEPT_LANGUAGE"] , um die im anfragenden Browser eingestellte Sprache abzufragen.
- request.ssl?
Liefert true zurück, wenn es sich um eine SSL-Abfrage handelt.
Datenbankabfragen über Model-Klassen 

Delegation an das Model
Wichtig ist, dass der Controller möglichst viel an das Model delegiert. Anstatt selbst eine Datenbankabfrage wie diese
@airports = Country.find(:first,
:conditions=>{:code=>'DE'}).airports
zu machen, sollte im Model eine Methode definiert werden, die diese Anfrage ausführt und die vom Controller aufgerufen wird.
@airports = Country.german_airports
Ein solcher Methodenaufruf lässt sich viel einfacher testen als eine Datenbankabfrage (siehe Kapitel »Test-Driven Development«) und erleichtert die Entwicklung dadurch ungemein.
Actions kurz halten
Allgemein sollten Sie daher darauf achten, dass Ihre Action nicht zu lang wird. Eine Action sollte in der Regel nicht mehr als 10 Zeilen enthalten.
Setzen und Abfragen von Cookies 

Um ein Cookie zu setzen oder abzufragen, können Sie die Methode cookies nutzen. Zum Setzen eines Cookies erwartet die Methode den Namen des Cookies und die einzelnen Werte in Form eines Hashs als Parameter:
cookies[:user_id] = {
:value => '8',
:expires => 2.hours.from_now}
Sie können folgende Optionen beim Setzen eines Cookies angeben:
- value:
Wert des Cookies oder eine Liste von Werten (als Array)
- path:
Pfad, für den das Cookie gültig ist. Standardmäßig ist das Root-Verzeichnis der Applikation eingestellt.
- domain:
Domain, für die das Cookie gültig ist
- expires:
Zeitpunkt (als Time-Objekt), zu dem das Cookie abläuft, wie z. B. 30.minutes.from_now .
- secure:
Gibt an, ob es sich um ein sicheres Cookie handelt oder nicht. Der Standardwert ist false . Sichere Cookies können nur zu HTTPS-Servern übertragen werden.
- http_only:
Gibt an, ob das Cookie über Scripting zugänglich ist oder nur über HTTP. Standardmäßig ist false eingestellt.
Kurzschreibweise
Wenn Sie nur den value setzen möchten, können Sie auch die Kurzschreibweise nutzen:
cookies[:user_id] = '8'
Abfragen können Sie ein Cookie einfach, indem Sie der Methode cookies den Namen des Cookies übergeben:
cookies[user_id]
# => 8
Cookie löschen
Mit folgendem Aufruf können Sie ein Cookie löschen:
cookies.delete :user_id
Setzen und Abfragen von Sessions 

Mit Hilfe von Sessions können Sie Objekte zwischen den einzelnen Anfragen zwischenspeichern. Das Speichern und Abfragen eines Objekts in einer Session ist ähnlich unkompliziert wie das Setzen und Abfragen eines Cookies.
Mit Hilfe der Methode session können Sie ein Objekt in einer Session speichern:
session[:user_id] = user.id
und ein Objekt aus einer Session abfragen:
@user = User.find(session[:user_id])
Die Methode session ist kein Hash, verhält sich aber wie params und cookies »hashlike«.
Session löschen
Mit folgendem Aufruf können Sie einen einzelnen Wert aus einer Session löschen:
session[:user_id] = nil
Eine komplette Session können Sie mit reset_session löschen.
Falls für einen Controller keine Sessions erforderlich sind, kann mit folgendem Befehl das Session-Management aus Gründen der Performancesteigerung deaktiviert werde:
class InfoController < ApplicationController
session :off
end
Templates aufrufen 

Instanzvariablen
In den Actions im Controller werden die dynamischen Inhalte, die in den Templates angezeigt werden sollen, ermittelt und in Instanzvariablen (Variablen mit führendem @-Zeichen) gespeichert, auf die die Templates zugreifen können, sie also als Templatevariablen nutzen.
template_root
Die Methode render, über die der Controller ein Template lädt, erwartet die Templates in dem Verzeichnis, das über die globale Variable template_root angegeben wurde. Standardmäßig ist das das Verzeichnis app/views . In einem Unterverzeichnis, das so heißt wie der Controller, werden die einzelnen Templates abgelegt. Die Templates sind nach den Actions innerhalb des Controllers benannt, von denen sie aufgerufen werden.
render
Durch Aufruf der Methode render wird das Template im Verzeichnis app/views/name_des_controllers aufgerufen, das so heißt wie die Action, aus der heraus die Methode aufgerufen wurde.
In dem folgenden Beispiel wird die Template-Datei new.html.erb aus dem Verzeichnis app/views/flights verwendet.
class FlightsController < ActionController
...
def new
@flight = Flight.new
render
end
...
end
Template auto- matisch laden
Zu diesem Zweck werden Sie die Methode render in der Praxis nicht nutzen, weil Rails automatisch am Ende einer Action das zugehörige Template lädt, wenn nichts anderes angegeben wurde. Das heißt, Sie können für diesen Fall auf den Aufruf der Methode render verzichten.
def new
@flight = Flight.new
end
Sie können der Methode render auch den Namen des Templates, das geladen werden soll, übergeben. In dem folgenden Beispiel wird die Template-Datei new.html.erb verwendet.
def new
@flight = Flight.new
render :new
end
Namen übergeben
Oder Sie übergeben den Namen des Controllers und den Namen des Templates:
...
render :template => "flights/new"
...
Sie können auch den absoluten Pfad zum Template angeben:
...
render :file => "/absoluter-pfad/flights/new.html.erb"
...
Statt ein Template aufzurufen, können Sie der Methode render auch einen Text übergeben, der an der Oberfläche ausgegeben werden soll:
...
render :text => "hello world!"
...
Option :layout
Mit der Option :layout können Sie angeben, ob eine Layout-Datei geladen werden soll und wenn ja, welche.
Standardlayout deaktivieren
Um das Standardlayout für das zu ladende Template zu deaktivieren, übergeben Sie false:
...
render :new, :layout => false
...
Anderes Layout verwenden
Wenn Sie ein anderes als das Standardlayout für ein Template laden wollen, geben Sie den Namen der Layoutdatei aus dem Verzeichnis app/views/layouts an:
...
render :new, :layout => "name_des_layouts"
...
Mehr zu Layout-Dateien erfahren Sie im Abschnitt »Layouts« in Kapitel »Templatesystem mit ActionView«.
Unterschiedliche Darstellungsformate
respond_to
Rails bietet uns eine sehr einfache Methode an, respond_to, die wir im Controller einsetzen können, um die Ausgabe im Template in unterschiedlichen Formaten zu realisieren:
def show
@flight = Flight.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => @flight.to_xml }
end
end
to_xml
Da das HTML-Format der Standardausgabe entspricht und es auch Standard ist, dass das passende Template zur Action im Controller geladen wird, müssen wir für den Fall, dass die Ausgabe in HTML erfolgen soll, nichts angeben. Im Fall der Ausgabe im XML-Format stellt uns ActiveRecord eine interessante Methode zur Verfügung, to_xml, mit der wir jedes ActiveRecord-Objekt in XML umwandeln können. Über render :xml erfolgt die Ausgabe im XML-Format.
Setzen von Flash-Nachrichten 

Statusmeldungen
Um dem Benutzer kurze Statusmeldungen, wie z. B. »Sie wurden abgemeldet« oder »Datensatz wurde erfolgreich gelöscht«, anzuzeigen, können sogenannte Flash-Nachrichten verwendet werden, die vom Controller gesteuert werden. Eine Flash-Nachricht ist ein Hash, der nur für eine Anfrage gültig ist und danach wieder gelöscht wird. Dies hat also nichts mit dem Adobe-Flash-Format zu tun.
Abbildung Beispiel einer Flash-Nachricht
:notice und :error
Bestätigungsmeldungen oder Notizen werden über die Flash-Nachricht flash[:notice] = "Text" an der Oberfläche ausgegeben. Mit der Flash- Message flash[:error] = "Fehlertext" können Sie auch Fehlermeldungen ausgeben.
Flash-Nachrichten müssen immer vor einer Weiterleitung (redirect_to) angegeben werden:
def create
@bookmark = Bookmark.new(params[:bookmark])
if @bookmark.save
flash[:notice] = "Favorit wurde erfolgreich angelegt."
redirect_to :action => "index"
...
end
end
Flash-Message ausgeben
Damit die Flash-Messages auch angezeigt werden, müssen wir sie in den entsprechenden Views ausgeben. Das könnte die index.html.erb sein, oder für den Fall, dass wir irgendwann einmal auch in anderen Views eine Flash-Message anzeigen wollen, können wir die Ausgabe auch in der application.html.erb vornehmen, da diese für alle Views gültig ist:
Listing app/views/layouts/application.html.erb
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<meta http-equiv="Content-type"
content="text/html; charset=utf-8">
<title>Favoritenverwaltung - <%= @title %></title>
<%= stylesheet_link_tag 'global' %>
</head>
<body>
<div id="container">
<div id="header">
<h1>Meine Linksammlung</h1>
</div>
<div id="content">
<%= flash[:notice] %>
<%= yield %>
</div>
</div>
</body>
</html>
Flash-Message formatieren
Wenn Sie die Ausgabe der Flash-Message formatieren möchten, können Sie in dem Template, in dem die Flash-Nachricht ausgegeben wird, einen Bereich um die Message herum setzen, den Sie dann in der CSS-Datei formatieren können. Damit der Bereich nur dann angezeigt wird, wenn eine Flash-Message gesetzt ist, müssen Sie das Template um eine Abfrage ergänzen, ob eine Flash-Message gesetzt ist.
Weiterleitungen 

redirect_to
Weiterleitungen werden eingesetzt, um auf eine andere Website weiterzuleiten oder um eine andere Action aufzurufen. Rails stellt uns dazu die Methode redirect_to zur Verfügung.
Eine Weiterleitung ist dadurch gekennzeichnet, dass sich durch ihren Aufruf in der Regel die URL verändert.
def destroy
@flight = Flight.find(params[:id])
@flight.destroy
respond_to do |format|
format.html { redirect_to(:action => "index") }
format.xml { head :ok }
end
end
redirect_to("http://www.railsbuch.de")
Um auf eine andere Website weiterzuleiten, übergeben Sie der Methode redirect_to die URL der Website.
redirect_to(:controller => 'countries', :action => 'show', :id => 5)
Um zu einer Action eines anderen Controllers weiterzuleiten, übergeben Sie den Namen des Controllers und der Action. Als zusätzlichen Parameter können Sie z. B. die ID übergeben, die von der Action verarbeitet wird.
redirect_to(:action => 'show', :id => 5)
Wenn Sie zu einer Action des gleichen Controllers weiterleiten möchten, können Sie die Angabe des Controllers weglassen und nur den Namen der Action übergeben. Optional können Sie auch hier weitere Parameter wie die ID übergeben, die von der Action empfangen und verarbeitet werden.
redirect_to(country_url(5))
Wenn Sie zu einer Ressource oder einer benannten Route weiterleiten möchten, können Sie die vom Routing zur Verfügung gestellten Methoden zur Angabe des Pfades nutzen. Im Abschnitt »Routing« in diesem Kapitel erfahren Sie mehr zum Thema Routing.
redirect_to(:back)
Wenn Sie zurück zu der Seite weiterleiten möchten, von der Sie auf die aktuelle Seite gekommen sind, können Sie der Methode redirect_to den Parameter :back übergeben. Die Weiterleitung erfolgt dann zum HTTP_REFERER.
Das ist besonders dann praktisch, wenn z. B. von mehreren Seiten auf ein Formular verlinkt wird und es über den Zurück-Link möglich sein soll, immer zur jeweiligen Vorgängerseite zu gelangen.
Senden von Dateien und Daten 

send_file
Streaming
Mit Hilfe der Methode send_file können Sie eine Datei als Datenstrom von jeweils 4.096 Bytes an einen Client-Rechner senden. Das hat den Vorteil, dass nicht erst die ganze Datei vor dem Versenden gelesen werden muss, und macht es deshalb möglich, große Dateien zu senden.
send_file erwartet den Pfad zu der Datei als Parameter:
send_file '/Pfad_zu/Datei.zip'
Achten Sie darauf, diesen Pfad genau zu prüfen, sollte er von einer Website gesendet werden. send_file(params[:path]) erlaubt es sonst unter Umständen einem böswilligen Benutzer, jede Datei auf Ihrem Server herunterzuladen.
Folgende Optionen können angegeben werden:
- filename:
Gibt einen Dateinamen-Vorschlag an, der beim Download angezeigt wird.
- type:
Setzt den HTTP Content-Type. application/octet-stream ist der Standardwert.
- disposition:
Legt fest, ob die Datei angezeigt oder zum Download angeboten werden soll. Mögliche Werte sind inline oder attachment . attachment ist der Standardwert.
- stream:
Legt fest, ob die Datei so gesendet werden soll, während sie gelesen wird ( true ), oder ob sie erst ganz gelesen werden soll, bevor sie gesendet wird ( false ). Der Standardwert ist true .
- buffer_size:
Legt die Zwischenspeichergröße (in Bytes) für das Streaming fest. Der Standardwert ist 4.096 Bytes.
- status:
Legt den Statuscode fest, der mit der Antwort gesendet wird. Der Standardwert ist 200 OK
- url_based_filename:
Setzen Sie diese Option auf true , wenn Sie möchten, dass der Browser den Dateinamen zum Speichern der Datei aus der URL liest. Für i18n-Dateinamen ist das in manchen Browsern erforderlich. Die Option filename überschreibt diese Option.
send_file '/Pfad_zur/Datei.pdf',
:type => 'application/pdf',
:disposition => 'attachment',
:filename => 'railsbuch.pdf'
send_data
Binäre Daten senden
Um Daten im Binärformat an einen Client zu senden, steht Ihnen die Methode send_data zur Verfügung. Die Methode erwartet als Parameter die binären Daten.
Folgende Optionen können angegeben werden:
- filename:
Gibt einen Dateinamen-Vorschlag an, der beim Download angezeigt wird.
- type:
Setzt den HTTP Content-Type. application/octet-stream ist der Standardwert.
- disposition:
Legt fest, ob die Datei angezeigt oder zum Download angeboten werden soll. Mögliche Werte sind inline oder attachment . attachment ist der Standardwert.
- status:
Legt den Statuscode fest, der mit der Antwort gesendet wird. Der Standardwert ist 200 OK .
Besonders praktisch ist diese Methode, um in der Datenbank binär gespeicherte Bilder im Browser anzuzeigen:
send_data image.data,
:type => image.content_type,
:disposition => 'inline'
Authentifizierung 

Um ein Authentifizierungssystem in Ihrer Applikation einzubinden, haben Sie mehrere Möglichkeiten.
HTTP-Authentifizierung
Mit Hilfe der Methode authenticate_or_request_with_http_basic, die uns ab Rails 2.0 zur Verfügung steht, ist es leicht, eine HTTP-Authentifizierung zu implementieren. Die Methode implementieren Sie im Controller und übergeben ihr einen Block, in dem Sie den Benutzernamen und das Passwort setzen.
Wir haben in Kapitel 3 eine HTTP-Authentifizierung in der Beispielapplikation employees eingesetzt:
Listing app/controllers/employees_controller.rb
class EmployeesController < ApplicationController
before_filter :authenticate
# GET /employees
# GET /employees.xml
def index
@employees = Employee.find(:all)
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => @employees }
end
end
...
private
def authenticate
authenticate_or_request_with_http_basic do |user,password|
user=="admin" && password=="geheim"
end
end
end
before_filter
Durch Aufruf der Methode before_filter :authenticate am Anfang des Controllers bewirken Sie, dass vor dem Ausführen jeder Action des Controllers die Methode authenticate aufgerufen wird. Damit die Methode authenticate nicht von außen aufrufbar ist, haben wir sie als private definiert.
Weitere Informationen zu Filtern und ihrer Funktionsweise erhalten Sie im Abschnitt 9.3.
Plug-in restful_authentication
Das Plug-in restful_authentication stellt zur Zeit als Nachfolger von acts_as_authenticated den De-facto-Standard für die Authentifizierung von Seiten in Rails dar.
Mehr Informationen zu diesem Plug-in, wie Sie es installieren und verwenden, erhalten Sie anhand eines praktischen Beispiels in Kapitel 15.
Ein eigenes Authentifizierungssystem entwickeln
Statt das Plug-in restful_authentication oder die HTTP-Authentifizierung zu nutzen, können Sie natürlich auch ein eigenes Authentifizierungssystem entwickeln. Wie das relativ einfach geht, zeigen wir in Kapitel 5.
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.