# Websiteentwicklung: Ruby on Rails/ Druckversion

* Druckversion des Buches Websiteentwicklung: Ruby on Rails
* Dieses Buch umfasst derzeit etwa 19 DIN-A4-Seiten einschließlich Bilder (Stand: 1.September 2009).
* Wenn Sie dieses Buch drucken oder die Druckvorschau Ihres Browsers verwenden, ist diese Notiz nicht sichtbar.
* Zum Drucken klicken Sie in der linken Menüleiste im Abschnitt „Drucken/exportieren“ auf Als PDF herunterladen.
* Mehr Informationen über Druckversionen siehe Hilfe:Fertigstellen/ PDF-Versionen.
* Hinweise:
* Für einen reinen Text-Ausdruck kann man die Bilder-Darstellung im Browser deaktivieren:
* Internet-Explorer: Extras > Internetoptionen > Erweitert > Bilder anzeigen (Häkchen entfernen und mit OK bestätigen)
* Mozilla Firefox: Extras > Einstellungen > Inhalt > Grafiken laden (Häkchen entfernen und mit OK bestätigen)
* Opera: Ansicht > Bilder > Keine Bilder
* Texte, die in Klappboxen stehen, werden nicht immer ausgedruckt (abhängig von der Definition). Auf jeden Fall müssen sie ausgeklappt sein, wenn sie gedruckt werden sollen.
* Die Funktion „Als PDF herunterladen“ kann zu Darstellungsfehlern führen.

## Vorwort

Lieber Leser, liebe Leserin,
Ruby on Rails (RoR) ist ein mächtiges Framework für die Entwicklung von Webapplikationen. Dieses Buch bietet einen schnellen Einblick in RoR - wenn man sich mit HTML, CSS, Javascript und einer serverseitigen Sprache wie z.B. PHP schon auskennt. Diese Version des Buches beschreibt Rails 3.2.6
Die Beispiel-Applikation, die im Laufe des Buches entwickelt wird, ist auch online:
* gesamter code als zip-Datei zum Download - achtung veraltet!
* hallo welt applikation auf heroku
Es gibt noch ein wesentlich umfangreicheres Wikibook Ruby on Rails für die Vertiefung.
Viel Spaß beim Lernen und Ausprobieren!

# Was ist Ruby on Rails

"Ruby on Rails" besteht aus zwei Teilen: Ruby ist eine Open Source Skriptsprache, ähnlich wie Perl oder Python. Ruby kann in verschiedenen Bereichen verwendet werden. Rails ist ein umfangreiches Web-Framework für diese Sprache.

## Was zeichnet Ruby aus?

* dynamische Sprache
* hoch-dynamische Community

## Was zeichnet Rails aus?
### DRY - Don't Repeat Yourself

Rails versucht Code-Verdopplungen zu vermeiden. Man schreibt immer sehr kurze Codes, und man kann viel damit erreichen.

### Convention over Configuration

Rails hat viele, viele Konventionen. z.B. wo die Dateien gespeichert werden, wie die Datenbanken heißen, u.s.w.
Wenn man sich an die Konventionen hält ist das Leben einfach, man hat wenig Arbeit, und alles funktioniert. (Wenn man sich nicht an die Konventionen halten will, kann man sich das Leben beliebig schwierig machen.)

### Model - View - Controller

Die Idee von Model - View - Controller wird in vielen Web-Applikationen verwendet. Es handelt sich um einen Pattern, der schon lange Zeit für die Erstellung von Benutzer-Interfaces verwendet wird.
Was MVC für ein eine Web-Applikation bedeutet, sei an einem konkreten Beispiel erklärt: Wir wollen ein Kursverwaltungssystem programmieren, in dem Leute Kurse buchen können.

#### Das Model

    ist ein Modell unseres Problemfelds. Für die Kursverwaltung brauchen wir also Kurse, User, Buchungen, etc. Diese sind in einer Datenbank gespeichert, in Tabellen namens kurse, user, buchungen. Für die Programmierung werden diese Datenbank-Tabellen auf Klassen umgelegt: in der Kurs-Klasse gibt es mehrere Kurs-Objekte. Dies erfolgt automatisch; wir brauchen - im Idealfall - keine einzige Zeile SQL zu schreiben.

#### Die View

    behandelt alle Probleme der Darstellung. Die View ist also eine Datei die hauptsächlich HTML, eventuell CSS und Javascript. Ein bisschen Ruby-Code sorgt für die Details der Anzeige, z.B. eine Schleife über alle User oder eine bedingte Anzeige: nur zukünftige Kurse.

#### Der Controller

    nimmt die Daten aus der URL und/oder die Parameter entgegen, ruft das richtige Modell auf, bereitet die richtigen Daten für die View vor... er hält also alles zusammen. Achtung: der Controller kann weder HTML noch SQL enthalten - das ist nicht seine Aufgabe!

### Tests

Rails unterstützt Dich beim Schreiben von automatisierten Tests. Damit kann man sehr gut Test Driven Development (TDD) machen: erst den Test schreiben, dann erst das Programm dazu.

## Wer verwendet Ruby on Rails?

Scribd und Slideshare sind wohl die berühmtesten Rails-Applikationen. In Europa verwendet XING (in Hamburg) Rails.

## Warum sollte ich 'nicht' RoR verwenden?

Für sehr kleine Web-Applikationen ist der Einsatz eines großen Frameworks wie Rails nicht sinnvoll.

# Die Sprache Ruby

Ruby ist eine Skriptsprache.

## Der Interpreter

Du kannst den Ruby-Interpreter direkt aufrufen und Befehle testen:

## Ein einfaches Skript

Ruby-Programme speichert man in Dateien mit der Endung .rb Hier ein einfaches Programm, nenne die Datei hallo.rb
Nun kannst Du das Programm auf der Kommendozeile starten:

## Datentypen, Kontrollstrukturen, Klassen

Wie in Skriptsprachen üblich verwendet man ein und dieselbe Variable für verschiedene Datentypen.
Im Unterschied zu anderen Skriptsprachen führt Ruby kaum automatische Typ-Konvertierung durch.
Ein paar einfache Beispiele:
https://gist.github.com/3462049

# Eine Ruby on Rails Applikationen von Außen

Woran erkennt man eine Rails-Applikation?
Betrachten wir dazu die Demo-Site von Redmine, einer Projektmanagement-Applikation die in Ruby geschrieben ist.
http://demo.redmine.org/

### URLs

Die URLs einer Rails-Applikation haben meist keine Endung, oft keine Parameter. Statt dessen ist die Information direkt im Pfad:
Dahinter stecken aber nicht Ordner in einem Filesystem, sondern diese URL wird auf Controller, Actions und Parameter umgeschrieben. der Kommandozeilen-Befehl rake routes zeigt die Regeln dafür an:
Die action index zeigt dabei eine Liste (der Boards) an, die action show zeigt ein einzelnes Board an.

## Für fortgeschrittene ProgrammiererInnen
### REST

Diese Struktur der URLs ist aber nur der offensichtlichste Teil eines tiefergehenden Plans. Nicht nur GET, sondern auch die anderen HTTP-Methoden werden verwendet:
Das ist die Grundstruktur die für verschiedene Ressourcen immer wieder gleiche verwendet werden kann. Die Idee dahinter ist REST.

### Webservice

Mit der Endung .xml kann die Rails-Applikation auch XML als Output liefern:
Damit bietet die Web-Applikation automatisch eine REST Webservice Schnittstelle an. Das kann man für AJAX verwenden oder als API für die Applikation.
(Oder man ignoriert es erst mal.)

# Erste Rails App
## Die Rails Applikation erzeugen

Bei der Arbeit mit Ruby on Rails spielt nicht nur der eigentliche Source-Code, sondern auch die Kommandozeile eine wichtige Rolle. Schon der erste Schritt passiert auf der Kommandozeile: um die Grund-Struktur der Rails-Applikation zu erzeugen wird der rails-Befehl aufgerufen:
Damit wird eine Reihe von Ordnern und Dateien erzeugt:
Die Kommandozeile wird auch weiterhin (mehrfach) gebraucht. (Ab jetzt sind alle Befehle im Hauptordner der App abzusetzen.)
Das Programm bundle installiert die richtigen Gems
Das Programm rake führt Befehle aus, die im Rakefile definiert sind. Bevor wir starten können, müssen wir die Datenbank mit folgendem Befehl erzeugen:
Nun können wir den Webserver auf der Kommandozeile starten:
Nun kann ich mir die App am localhost auf port 3000 im Browser ansehen:

## Scaffolding

Nach dem Model-View-Controller Prinzip müssen wir für unsere Datenbank der Hallo-Welt Meldungen
* eine Tabelle in der Datenbank anlegen
* ein Model erzeugen
* einen Controller (mit eventuell verschiedenen Actions) erzeugen
* für die Actions jeweils Views erzeugen
Rails hilft uns, das Alles auf einmal zu machen.

### Scaffold erzeugen

Dazu verwenden wir das generate-script und erzeugen damit ein scaffold - ein Gerüst:
Das erste Argument hallo ist der Name des Modells, danach folgen die Eigenschaften und Datentypen des Modells.
In diesem Fall will ich zu jedem "hallo" abspeichern: von dem die Meldung ist, den Text der Meldung und welche Farbe die Meldung haben soll.
Nun müssen wir noch die Datenbank-Tabelle wirklich anlegen, das geschieht mit

### Die Datenbank

Mit dem Befehl
startet man eine shell für die Datenbank. Hier kann man z.B. mit
die gerade angelegte Tabelle betrachten:
Als Name für das Modell hatten wir Hallo gewählt, rails hat automatisch die Mehrzahl für die Bezeichnung der Tabelle gewählt.
Ein Primärschlüssel namens id und die beiden Felder created_at und updated_at wurden ebenfalls automatisch angelegt.
Die Datentypen wurden auch von Ruby auf Datenbank übersetzt: aus string wurde varchar(255).

### Das Modell in app/models/hallo.rb

Die Klassen-Datei für das Modell wurde angelegt, ist aber noch leer.
Hier könnten wir Methoden eintragen die die innere Logik des Modells abbilden.
Für die Validierung der Daten bietet Rails viele Praktische Kurz-Schreibweisen an. Wenn wir z.B. sicherstellen wollen, dass als Farbe nur ein HTML-Farbcode wie #FF0033 gespeichert werden kann, dann reicht dazu eine Zeile im Modell:
Das erste Argument ist der Name der Spalte / der Eigenschaft, mit dem benannten Argument :with gibt man eine Regular Experssion zur Überprüfung an, und mit :message eine passende Fehlermeldung.

### Der Controller in app/controllers/hallos_controller.rb

Diese Datei ist umfangreich: sie enthält 7 vorgefertigte Actions:
* index - listet alle Meldungen auf
* show - zeigt eine bestimmte meldung an (ID notwendig!)
* new - zeigt ein Eingabeformular für eine neue Meldung an (weiter bei create)
* edit - zeigt eine Meldung in einem Bearbeitungsformular an (ID notwendig!, weiter bei update)
* create - erzeugt eine neue Meldung
* update - verändert eine Meldung
* destroy - löscht eine Meldung (ID notwendig!)
Betrachten wir die einfachste Action: show zeigt eine bestimmte Meldung an. Beim Aufruf dieser Action muss eine id als Parameter übergeben werden:
Über den Parameter id wird der Datensatz Hallo als Objekt geladen und in der Instanzvariable @hallo des Controllers gespeichert.
Die Action funktioniert aber nicht nur für den Fall, dass Sie HTML als Output liefern soll. Auch JSON als Output ist vorgesehen. Dafür sind 4 weiter Zeile Code notwendig:

### Routing - von der URL zur Action

Mit dem Kommandozeilen-Befehl rake routes kann man sehen wie URLs, Controller, Actions zusammen hängen. Dies wird in der Datei config/routes.rb festgelegt, wurde aber durch das Scaffolding automatisch erledigt. Hier der Output von rake routes:
Ganz links ist für manche Routes ein Name angegeben, den man innerhalb von Views und Controllern verwenden kann. In der zweiten Spalte finden Sie die HTTP Methode, anschießend die URL und zuletzt die Kombination von Controller und Action die hier aufgerufen werden.
Die erste Route hallos ruft die action index auf und alle Hallo-Meldungen werden angezeigt.
Die route mit dem namen hallo (3.von unten) bedeutet also: Wenn mit GET ein Aufruf von http://localhost:3000/hallos/14 erfolgt, dann wird der Controller hallos mit Action show aufgerufen. Wo :id steht kann also eine Zahl eingesetzt werden. Wo :format steht kann json eingefügt werden: Wenn mit GET ein Auftruf von http://localhost:3000/hallos/14.json erfolgt, dann wird der Controller hallos mit Action show aufgerufen, er soll dann JSON als Output produzieren.
Nun wäre ein guter Zeitpunkt die Applikation auszuprobieren und ein paar Meldungen einzufügen, wieder zu verändern oder zu löschen

### Die Views in app/views/hallos/*.html.erb

Vier Views wurden automatisch angelegt:
* index.html.erb - listet alle Meldungen auf
* show.html.erb - zeigt eine bestimmte meldung an (ID notwendig!)
* new.html.erb - zeigt ein Eingabeformular für eine neue Meldung an (weiter bei create)
* edit.html.erb - zeigt eine Meldung in einem Bearbeitungsformular an (ID notwendig!, weiter bei update)
Das Format der Views ist Embedded Ruby (Endung .erb). Eine View besteht hauptsächlich aus HTML, mit <% ... %> kann Ruby eingebettet werden das ausgeführt wird. Mit <%= ... %> kann Ruby eingebettet werden das Output liefert. Dabei werden hauptächlich die Instanz-Variablen des Controllers verwendet.
Die View show.html.erb zeigt eine Meldung an.
Die beiden letzten Zeilen erzeugen zwei Links. Das erste Argument von link_to ist der Link-Text. Das zweite Argument ist die URL. Hier werden Methoden aufgerufen, die automatisch für alle benannten routes vorhanden sind (siehe rake routes).
Die route hallo braucht keine Parameter, mit hallo_path erhält man die URL ohne Hostnamen, mit hallo_url die vollständige URL.
Bei edit_hallo ist es etwas komplizierter: diese Route muss wissen, welches Objekt gemeint ist. Hier kann man als Argument entweder das ganze Objekt oder nur die id des Objekts übergeben. Auch hier gibt es wieder die Formen edit_hallo_path und edit_hallo_url.
Die Darstellung der Meldung können wir ganz verändern: Die Farbe wird wirklich als Farbe verwendet und nicht als Text angezeigt
Verändern Sie auch index.html.erb so, dass die Farbe wirklich als Farbe verwendet wird! Achtung: in der index-View gibt es zwei Variablen: @hallos ist ein Array aller Meldungen, hallo ist die jeweils aktuelle Meldung.

## Eine neue Homepage einsetzen

Der hallo-Controller wäre ein sehr gut Homepage für unsere 'Hallo Welt' Applikation. Um das zu erreichen, muss man die Datei public/index.html löschen und in config/routes.rb folgende Zeile einfügen:
Damit ist die erste Webapplikation in Ruby on Rails fertig.
* ↑ Tilkov(2007): A Brief Introduction to REST. In: InfoQ.
* ↑ Rails Guide Validations

# Konfiguation und Datenbank

Wenn man ein Projekt mit
startet, speichert Rails die Daten in einer sqlite-Datenbank. Das ist besonders einfach: alle Daten sind in der Datei db/development.sqlite3 zu finden.
Wenn man das Projekt gleich mit
startet wird statt dessen mysql verwendet. Nun wollen wir uns näher mit der Konfiguration befassen und dabei lernen wie man ein laufendes Projekt auf ein mysql-Datenbank umstellt.

### Konfigurations-Dateien

Im Ordner config sind u.a. folgende Dateien zu finden:

#### database.yml

    Konfiguration der Datenbanken für die verschiedenen Server

#### routes.rb

    Konfiguation der URLs und ihrer Umrechnung auf Controller und Actions

#### environment.rb

    weitere Konfiguration

#### locales/en.yml

    Texte für die englische Version der Website (hier könnte man de.yml, it.yml, u.s.w. einfügen)

### Datenbank

Die Datei database.yml enthält normalerweise folgenden Code:
Hier sehen wir dass in Rails von Anfang an drei verschiedene Server vorgesehen sind:

#### development

    ist die Datenbank für die Entwicklung, wenn ich das Programm schreibe und ausprobiere

#### test

    ist die Datenbank für die automatischen Tests. Diese Datenbank wird auch automatisch erzeugt und wieder gelöscht

#### production

    ist die Datenbank für den Echt-Betrieb
Wenn ich mysql statt sqlite verwenden will muss ich einerseits entsprechende Datenbanken in meinem MySQL Server anlegen und andererseits die Konfigurationsdatei ändern. Hier ein Beispiel für das Projekt 'chor': (Achtung beim Kopieren dieses Codes: diese Konfigurationsdatei verträgt keine Tabulatoren und keine Leerzeichen vor development, test, production!)
Die Konvention, an den Applikationsnamen mit Unterstrich etwas anzuhängen um den Datenbanknamen zu erzeugen hat eine angenehme Nebenwirkung: in phpmyadmin werden die Datenbanken gruppiert.

# Datenbank und Model

Wie arbeiten Datenbank und Model zusammen?

## Datenbank verändern mit Migrations
### Die Problemstellung

Bei Web-Applikationen tritt folgendes Problem auf: im Laufe der Entwicklung ändert sich das Datenbank-Schema. Gleichzeitig ist die Applikation aber schon im Echt-Betrieb, man kann die Produktions-Datenbank nicht einfach löschen und von Grund auf neu bauen.
Es ist also notwendig, die Veränderungs-Schritte der Datenbank zu speichern, und auf allen Servern (verschiedene Entwicklungs-Rechner, Test, Produktion) in der gleichen Reihenfolge nachzuvollziehen.
Ruby on Rails bietet dafür eine Lösung: Migrations.
Eine Migration ist dabei ein Schritt der Veränderung - wobei dieser Schritt immer in beide Richtungen definiert ist.
Im Ordner /db/migrations/ sind die einzelnen Migrations gespeichert.
Nach der Erzeugung des scaffolds für hallo sieht das z.B. so aus:
Diese Datei enthält das Anlegen der Tabelle für das Model Hallo:

### Eine Migration erstellen

Mit dem Kommandozeilen-Befehl
werden jeweils alle neuen Migrations ausgeführt. Mit
kann der letzte Schritt rückgängig gemacht werden. Welcher Migrations-Schritt bereits angewandt wurde wird in der Datenbank salbst gespeichert, in der Tabelle schema_migrations
Wenn man die Datenbank verändern will - zum Beispiel um eine neue Spalte in die Tabelle einzufügen - so kann man selbst eine migration erzeugen:
Aus der Namens-Konvention erzeugt der Generator gleich einen guten Entwurf für die Migration:

### Was noch zu tun ist

Nach dem Hinzufügen oder Löschen von Spalten aus der Tabelle muss das Model nicht verändert werden! Die Spalten werden automatisch als Attribute des Objekts übernommen. Der Controller muss meist auch nicht verändert werden.
Nur die Views (Eingabemasken, Anzeige des Objekts) müssen verändert werden!

## Daten lesen und speichern mit dem Model

Wir arbeitet das Model mit der Datenbank zusammen? Das werden wir nun interaktiv erforschen

### Daten Suchen und Finden

Es gibt eine interaktive Shell für Rails. Gestartet wird sie mit
Nun kann man ruby-befehle eintippen und sieht sofort das Ergebnis.
Die Klasse Hallo hat (wie jedes Klasse des Models) eine Methode find. Mit find(1) suche ich nach dem Objekt das in der Datenbank die id=1 hat.
Mit find(:all) suche ich nach allen Objekten. Das gibt viel output (hier gekürzt!)

### Daten anlegen

Hier kann man auch neue Objekte anlegen:
das Objekt existiert derzeit nur im Hauptspeicher, im laufenden Programm - es ist noch nicht in der Datenbank gespeichert. (Deswegen hat es auch noch keine id). mit save kann ich versuchen das Objekt zu speichern:
Der Rückgabewert false bedeutet: das Speichern hat nicht funktioniert. Warum? Weil die Farbe nicht gespeichert werden kann, ich habe ja eine Validierung auf dem Farb-Feld Programmiert:
Also muss ich die Farbe korrekt setzen und kann dann speichern:
Danach hat h auch eine id, und werte in created_at und updated_at:

# Controller und View

* ↑ Rails Guide Migrations
* ↑ Rails API ActiveRecord Migration

# Views, Partials und Layouts

Beim Schreiben der View ist Dir vielleicht aufgefallen, dass nirgendwo ein head oder body zu lesen ist. Diese Teile der Webseite, die für die einzelnen Seiten der Applikation gleich sind, werden nicht in der View selbst gespeichert:

## Layout

Für eine einfache Webapplikation brauchen wir nur ein Layout: es heisst application.html.erb.
Die vom Scaffold erstellte Datei enthält HTML5, und an vier Stellen Ruby:
* ein Link zum (gesammelten) Stylesheet
* ein Link zum (gesammelten) Javascript
* ein Tag der Code einfügt, der Cross Site Request Forgeries verhindert
* der Befehl yield, hier wird die View eingefügt
Eine Veränderung im Layout kann beim Verständnis der Applikation helfen: Im Titel geben wir automatisch den Controller und die Action aus:

## Partials
### Einfaches Partial

In den Views edit.html.erb und new.html.erb wird genau das selbe Formular verwendet. Dieses Formular ist deswegen nur einmal gespeichert, in einem Partial. In beiden Views steht nur
Achtung: damit wird die Datei _form.html.erb geladen! (Beachte den Unterstrich!)
Das Partial selbst enthält einfach den Code mit dem Formular.

### Partial mit Schleife

Die Darstellung der hallo-Meldungen in show und index können wir auch vereinheitlichen. Wir erzeugen ein Partial _meldung.html.erb', das eine einzelne Meldung darstellt. Diese Meldung ist in der Varialbe meldung zu finden - das ergibt sich aus dem Dateinamen des Partials:
Dieses Partial kann nun in der View von show einfach aufgerufen werden:
In der View von index war bisher eine Schleife über das Array @hallos nötig. Dies entfällt mit dem Aufruf des Partials mit dem Argument :collection:

## Absolute Links und URLs vermeiden

Wir haben schon verschiedene Methoden kennen gelernt, wie wir vermeiden können fixe URLs zur programmieren:
Analoges gibt es auch noch für Bilder:
Für Javascript gibt es auch eine Standard-Einstellung, damit wird normalerweise jquery geladen:
Hinter all diesen Tags steckt fortgeschrittene Magie: die Asset Pipeline.

# Weitere Quellen

* Auf Englisch: Rails Guides
* Auf Englisch: Buch Rails for PHP Developers

# jQuery

Rails unterstützt die Verwendung der Javascript-Library jQuery.

## Beispiel

Bei der Anzeige der Meldung sollen die Bearbeitungs-Links (show, edit, destroy) unsichtbar sein bis man mit der Maus über die Meldung fährt. Dazu wird der HTML-Code nicht verändert, nur zwei Klassen werden eingeführt: sensor bezeichnet den Bereich der auf die Maus reagieren soll, hide_until_hover muss innerhalb von sensor sein und bezeichnet den Bereich der versteckt wird.
Dazu noch der etwas veränderte Code der hallos/index view:
Da dieses Javascript nur in den Views von "Hello" gebraucht wird, fügen wir in die Datei app/assets/javascripts/hallos.js ein:
Hinweis: es existiert eine leere Datei app/assets/javascripts/hallos.js.coffee. Hier könnte man CoffeeScript einfügen, dass dann in einem separaten Schritt zu Javascript kompiliert wird. Man kann diese Datei einfach löschen, wenn man lieber direkt in Javascript arbeiten will.

# Testen

Bei Web-Applikationen, die nicht nur einmal veröffentlicht, sondern auch dauernd weiter entwickelt werden, ist es besonders wichtig automatische Tests zu haben: Wenn ich ein neues Feature einbaue kann ich anschließend die Tests laufen lassen, und somit sicher sein, dass die Applikation noch funktioniert.

## Die Test-Umgebung

Im Ordner test findet man den Code den man für Tests schreibt. Ein weiterer Teil der Test-Umgebung ist die Datenbank, die in config/database.yml definiert wurde.
Bevor man Tests startet muss man die Test-Datenbank auf den neuesten Stand bringen:

## Unit Tests

Die Unit-Tests testen die einzelnen Klassen des Models. In unserem sehr einfachen Beispiel-Programm gibt es noch nicht viel zu testen:
In der Datei \test\unit\hallo_test.rb:
Um diesen Test durchzuführen muss man auf der Kommandozeile in den ordner test wechseln:

## Functional Tests

Diese Tests prüfen die Funktion der Controller. Durch das scaffolding wurde schon für jede Action ein Test erstellt. Den Test kann man wieder direkt starten:
In dieser Datei ist die Schreibweise etwas anders: jeder Test beginnt mit dem Wort 'test' und einem Namen als String.
hallos(:one) ist ein verweis auf eine "Fixture". Das sind Test-Daten, die vor dem Testlauf aus einer Datei in die Datenbank geladen werden.
So könnte die Datei \test\fixtures\hallo.yml aussehen:
Achtung: dies ist wieder eine Datei im yaml-Format (so wie database.yml), die sehr empfindlich auf einrückungen reagiert!
Damit wird ein Datensatz definiert, der von den Test-Dateien aus als hallos(:one) erreichbar ist.

### Integration Tests

Alle bisherigen Tests betrachten Details: nur ein Modell, oder nur einen Schritt beim Aufruf über das Web. Für das "große Ganze" gibt es noch Integration Tests. Diese verwendet man zum Beispiel, um zu testen ob das Login funktioniert, und ein User nach dem Login bestimmte Recht hat - also Szenarien mit mehreren Schritten.
Integration Tests werden nicht automatisch erzeugt.

### Ausblick: Cucumber

Mit Cucumber kann man die intendierte Funktion der Webseite auf "Pseudo-englisch" oder "Pseudo-Deutsch" beschreiben. Damit eignet es sich gut um mit Nicht-Programmierern gemeinsam die Tests zu schreiben.
Wenn alle Tests erfolgreich durchlaufen wird Cucumber grün - deswegen ist es nach der Gurke benannt:

# Assoziationen

Zwei Modelle sollen eine Beziehung haben, zum Beispiel: zu jeder unserer Hello-Meldungen soll es mehrere Comments geben können, jedes Comment gehört zu genau einem Hallo. Dies nennt man eine 1:n Assoziationen.

## Modell und Datenbank

Diese Beziehung passiert auf zwei Ebenene: im Modell und in der Datenbank.
In den beiden Modellen wird die Beziehung so aussehen:
In der Datenbank gibt es einen Fremdschlüssel hallo_id in der comment-Tabelle.
Wenn man das gleich von Anfang an bedenkt kann man diesen Schlüssel schon beim scaffold mit erzeugen lassen:
Unter der URL http://localhost.3000/comments/ kann man jetzt Comments anlegen
Die Objekte sind auf foglende Weise miteinander verbunden: man kann von einem comment immer zu seinem hallo gelangen und umgekehrt:

## Routes

Bei einer belongs_to/has_many Beziehung macht es Sinn, die URLs zu verschachteln: Ein Comment ist immer einem Hallo zugeordnet.
Dies erreicht man mit folgender Änderung in config/routes.rb
Nun können wir die Controller und Views ausprobieren: die URL zum Einstieg lautet http://localhost:3000/hallo/1/comments

## Controller

Im comments_controller erhalten wir immer den Parameter hallo_id. Wir können also bei jeder einzelnen Action folgende erste Zeile eintragen:
Statt das 7mal einzutragen gibt es eine einfachere Möglichkeit: einen before_filter. Die im before_filter angegebene Funktion wird vor jeder Action ausgeführt. Da die Funktion in eine Instanz-Variable schreibt (erkennbar am @ vor dem Variablennamen) ist die Information dann auch in der Action verfügbar.
Die Methoden create muss auch angepasst werden: das Kommentar wird nicht einfach als Objekt der Klasse Comment erzeugt, sondern wir verwenden die build Methode des Objekts @hello:
Im index wollen wir nicht alle comments der Datenbank (Comments.all) anzeigen, sondern nur diejenigen, die zum akutellen Hallo gehören:

## Neue URLs in Views und Controller

In den Views des comment-Controllers kann man jetzt auch @hallo lesen.
In den Views muss man viele Pfade ändern. Ein Beispiel:
aus comment_path wird hallo_comment_path(@hallo)
Am einfachsten ist es sich die Routes anzeigen zu lassen, um heraus zu finden wie die neue Version der einzelnen Methoden lautet.
Vorher:
Nachher:
Analog für form_for: auch das Formular muss einen längern Pfad benutzen:
Das Eingabefeld für hallo_id kann man dafür ersatzlos streichen: der Parameter hallo_id wird aus der URL übernommen.
Wenn man nun ein neues Comment speichern will gibt es ein Problem mit dem Controller:
Das Erzeugen und Abspeichern des Comments funktioniert schon richtig, das Problem tritt danach auf:
Hier soll zur show-action des neu angelegten Comments umgeleitet werden. Da Comments nun eine verschachtelte Ressource ist, müssen wir die entsprechende URL verwenden:

# Vereinfachen

Die Views, die das Scaffolding für unsere automatisch erzeugt hat, sind nicht miteinander verbunden: Hallos linkt zur zu Hallos-Views, Comments zur zu Comments-Views. Das ist nicht gut zu bedienen, und eigentlich unpraktisch
Nun wollen wir diese Views vereinfachen, und leichter bedinbar machen.

## Welche View bleibt?

Durch die Vereinfachung werden einige Views wegfallen - aber welche? Betrachent wir folgende routes:
Nummer 2 und Nummer 3 würden sich beide eigenen, um ein Hallo mit allen Kommentaren dazu anzuzeigen. Betrachten wir an die dahinter liegenden Controller: im comments_controller wird @hallo schon gefunden und geladen. D.h. es ist einfach, es auch in der View anzuzeigen. Im hallos_controller werden keine Kommentare geladen. Deswegen ist es einfacher, Nummer 2 nicht weiter zu verwenden, und überall durch Nummer 3 zu ersetzen.

## View zeigt Hallo und Kommentare

Wir können in die view comments/index.html.erb einfach Code zur Darstellung des Hallos einfügen:

## Neu verlinken

In der View hallos/index.html.erb können wir nun die Show-Links verändern: statt
auf

# User und Login

In diesem Kapitel werden wir eine App um eine n:m Beziehung erweitern: Ausgangspunkt ist tvtogether, eine App die Serien und Folgen von tvrage.com laden kann.
In diesem Kapitel werden wir als ersten Schritt in die App die Möglichkeit einbauen, dass User sich anmelden, einloggen und ausloggen. Dabei unterstützt uns Rails 3 sehr, wir brauchen nur wenig selbst zu Programmieren.
Diese App werden wir um ein Model 'user' erweitern. Zwischen users und episodes besteht eine n:m Beziehung: eine Person kann mehrere Episoden gesehen haben, eine Episode wurde von mehreren Personen gesehen.

## User und Authentisierung

Wir werden ein Model "User" brauchen, das Namen, E-Mail und das gehashte Passwort gespeichert.
Ausserdem werden wir den Hash session verwenden. Dieser wird von Rails zur Verfügung gestellt. Daten die wir hier speichern sind noch vorhanden, wenn vom gleichen Browser auf die nächste Seite aufgerufen wird. (Das wird mittels Cookies erreicht, diese werden automatisch von Rails gesetzt)

### User

Diese Funktionalität braucht ein zusätzliches gem: Wir fügen in das Gemfile ein:
und führen danach einmal
aus. Damit wird das gem installiert. Damit es in der App verwendet wird, müssen wir den Webserver stoppen (mit STRG-C) und neu starten
Nun legen wir das User-Model an.
Dem Model fügen wir eine Zeile hinzu:
Diese eine Zeile fügt sehr viel Automatik ein: Methoden zum Setzen und Verifizieren des eingegeben Passworts, validations. In der Datenbank wird dabei nie das Original-Passwort gespeichert, sondern nur eine gehashte Version. Damit sich neue User anmelden können brauchen wir einen Controller:
Der Code des Controllers ist kurz:
Und dann brauchen wir noch eine View zur Anmeldung:

### Session, Login, Logout

Wie oben erwähnt ist die session ein Hash in Rails der in jedem Controller zugänglich ist, ähnlich wie params. Wir werden nun aber so tun, als ob sesssion ein model wäre, und eine View und einen Controller dafür anlegen.
Das Login-Formular wird as view sessions/new gespeichert. Dies ist das erste Formular, das nicht mit form_for erstellt wird, sonder mit from_tag. Der Unterschied: form_for ist immer an ein Model gebunden, mit form_tag kann man beliebige Formulare ganz unabhängig von Datenbank und Model, erzeugen.
Zu dieser View gehört ein Controller:
Der Controller hat 3 Actions, eine ist hier noch nicht vollständig implementiert:
Wenn das Login erfolgreich ist speichern wir die user_id in der Session - und nicht mehr.
Wie können wir nun prüfen ob der Login erfolgreich ist? Zuerst holen wir den user mit der Passenden E-Mail aus der Datenbank. Mit der authenticate-Methode des user-Objekts können wir prüfen ob das Passwort passt:
Damit wir in jedem Controller und jeder View die Information zur Verfügung haben ob jemand eingeloggt ist legen wir im applications_controller eine helper-Funktion an:

### Navigation mit Login und Logout

Ähnlich wie hier in Wikibooks soll auch in der App tvtogether oben auf jeder Seite angezeigt werden ob mein eingloggt ist, bzw. Links für Login und Logout angeboten werden.
Das kann man in das Layout einfügen: app/views/layouts/application.html.erb

# n:m Beziehung

In diesem Kapitel werden wir weiter an der App tvtogether arbeiten. Zwischen users und episodes besteht eine n:m-Beziehung: eine Person kann mehrere Episoden gesehen haben, eine Episode wurde von mehreren Personen gesehen.
In einer relationalen Datenbank braucht man für die Darstellung einer n:m-Beziehung eine Zwischentabelle. Es es sinnvoll, aus dieser Zwischentabelle ein sogenanntes "Join Model" zu machen.

### Join Model

Die drei beteiligten Modelle haben dabei folgende Beziehungen:
Wie soll das Join-Modell in unserem Projekt heißen? hat_gesehen? seen? oder denken wir schon weiter zu einem Rating: meinung? rating? Ich habe mich dann für rating entschieden:
So sehen die Models aus:

### Join Model auf der Console

Bevor wir mit dem Join-Model etwas programmieren, erforschen wir es interaktiv auf der Rails-Console:
Die letzte Schreibweise, mit den ids, kann man auch für Zuweisungen verwenden:
Hier werden also eventuell vorhandene Ratings gelöscht, und dann für die drei neuen Episoden Ratings eingefügt.

### Controller und View

Wir bauen nun eine edit_user View, die immer eine Liste aller Episoden anzeigt. Bei jeder Episode gibt es eine Checkbox die für die Rating-Beziehung steht.
Hier ein erster Entwurf der View:
Die params die dieses Formular liefert sehen z.B. so aus:
So werden die Checkboxes im user_controller verarbietet: die episode_ids müssen gar nicht extra behandelt werden:
Nur im user-Model müssen sie als attr_accessible eingetragen werden:
Was das Formular noch nicht kann: die Checkboxes sind nie bereits angeklickt, auch nicht wenn in der Datenbank bereits ein Rating exisitert.
Bei Formularfelder die über den from_for Tag erzeugt ist das immer automatisch gegeben: Sie spiegeln den Zustand des Models wieder.
Diesen Checkboxes müssen wir "von Hand" setzen:

# Anhang: Installation unter Windows

http://railsinstaller.org/

# Weitere Quellen

* Auf Englisch: Rails Guides
* Auf Englisch: Buch Rails for PHP Developers

## Verwendete Quellen

* ↑ Rails Guide Layouts and Rendering
* ↑ Rails API AssetTagHelper
* ↑ Rails Guide Asset Pipeline
* ↑ Rails Guide Testing
* ↑ Hellesøy: Cucumber
* ↑ Rails Guide Active Record Associations
* ↑ Rails Guide Layouts and Rendering in Rails
* ↑ Railscast Authentication in Rails 3.1
* ↑ Railscast HABTM Checkboxes (revised)