7H[LU[PLY[L)PUK\UN :*/5,33,9A<4A0,340;9<)@659(03: 5L\+PL(\ÉHNLKLJR[9HPSZHILU[OjS[LPU2HWP[LSa\+LWSV`TLU[TP[ *HWPZ[YHUV\UKLPURVTWSL[[mILYHYILP[L[LZ2HWP[LSa\Y0U[LYUH[PVUHSPZPLY\UN 7YVÊ[PLYLU:PL]VUKLT2UV^OV^KLY(\[VYLUH\ZPOYLU9HPSZ7YVQLR[LU (SSL;PWWZ\UK)LPZWPLSLPUKLY7YH_PZNL[LZ[L[ +PL^PJO[PNZ[LU,SLTLU[L\UK(U^LPZ\UNLU]VU9\I`7YVNYHTTLUHSZ WYHR[PZJOLY)LPOLM[LY 0T0U[LYUL[!,PULRVTWHR[L\UKOPSMYLPJOL,PUMmOY\UNPU9\I`LPU]VUKLU (\[VYLUIL[YL\[LZ-VY\T\UK]PLSLZTLOY 3LYULU:PLTP[/PSMLKPLZLZ)\JOLZKH[LUIHURIHZPLY[L\UKNLZJOjM[ZRYP[PZJOL >LI(U^LUK\UNLUa\LU[^PJRLSU\UKPU7YVK\R[PVUa\IYPUNLU<UKKHZTP[ \UNLHOU[LY7YVK\R[P]P[j[<UK]VU(UMHUNHUTP[LPULYZH\ILYLU(YJOP[LR[\Y KPL>HY[IHYRLP[\UK3HUNSLIPNRLP[ZPJOLYZ[LSS[:PLLYMHOYLUH\JO^PLZPJO0OYL (U^LUK\UNLUPU[LYUH[PVUHSPZPLYLU\UKKHTP[H\JOKL\[ZJOZWYHJOPNL3lZ\UNLU LU[^PJRLSUSHZZLU 5L\PUKLYa^LP[LU(\ÉHNLZPUK\U[LYHUKLYLTKPL)LZJOYLPI\UNKLYUL\LU -LH[\YLZ]VU9\I`VU9HPSZ\UKLPU2HWP[LSa\T+LWSV`TLU[TP[*HWPZ[YHUV +HZ2HWP[LSmILY0U[LYUH[PVUHSPZPLY\UN^\YKLRVTWSL[[mILYHYILP[L[,ZILZJOYLPI[ KPLILPKLUNjUNPNZ[LU3lZ\UNLU!9\I`.L[[L_[\UK.SVIHSPaL +HZ)\JOPZ[KLTPU[LYLZZPLY[LU,U[^PJRSLYZLOYa\LTWMLOSLULU[^PJRSLYTHNHaPU 9HSM>09+,4(55\UK;OVTHZ)(<:;,9;ZPUKHULYRHUU[L,_WLY[LUMmYKPL ,U[^PJRS\UNVIQLR[VYPLU[PLY[LY:VM[^HYLZ`Z[LTL:PLILZJOjM[PNLUZPJOZLP[ TP[9\I`VU9HPSZ\UKOHILUILYLP[ZTLOYLYLRVTTLYaPLSSL9HPSZ(U^LUK\UN LU[^PJRLS[ZV^PL>VYRZOVWZa\9HPSZK\YJONLMmOY[:PLZPUK(\[VYLUaHOSYLPJOLY -HJOHY[PRLS\UKNLMYHN[L:WLHRLYH\M2VUMLYLUaLU+PLZLZ)\JOMVSN[POYLT4V[[V IZPTWSLTP[KLTZPLPOYL2\UKLU\U[LYZ[m[aLULPUMHJOL\UKHUNLTLZZLUL >LNLMmYKPL,U[^PJRS\UN]VU:VM[^HYLa\ÊUKLU 2!0)$7%"$%6%,/0-%.4-)4 25"9 /.2!),3 9\I`VU9HPSZOH[KPL>LPJOLUUL\NLZ[LSS[PUW\UJ[V7YVK\R[P]P[j[ (NPSP[j[\UK,PUMHJOOLP[ILPKLY,U[^PJRS\UNTVKLYUZ[LY>LIHWWSPRH [PVULU=LYWHZZLU:PLUPJO[KLU(UZJOS\ZZKPLZLZ)\JOPZ[0OY;PJRL[ a\LPULYIPZOLY\UNLHOU[LU3LPJO[PNRLP[PUKLY:VM[^HYLLU[^PJRS\UNMmY KHZUL\L>LI -YHUR>LZ[WOHS,_[YLTL7YVNYHTTLY*VHJO !UmAGE ^^^OHUZLYKLJVTW\[LY 0:)5! 0:)5! >LI,U[^PJRSLY7YVNYHTTPLYLY 2!0)$7%"$%6%,/0-%.4-)4 9(70+>,)+,=,3674,5;40;9<)@659(03:A^LP1HOYL9HPSZA^LP 1HOYLKPLNLaLPN[OHILU!>LY9HPSZHU^LUKL[WYVÊ[PLY[]VUKL\[SPJOZJOULSSLYLU ,U[^PJRS\UNZaLP[LU\UKLYSLI[LPULUL\L3LPJO[PNRLP[KLY:VM[^HYLLU[^PJRS\UN 2LPU>\UKLYKHZZKPLAHOSKLY9HPSZ(UOjUNLY\UKKLYRVTTLYaPLSSLU9HPSZ 7YVQLR[LZ[jUKPNZ[LPN[ 25"9/.2!),3 7)2$%-!.. "!534%24 RALF7)2$%-!.. THOMAS"!534%24 Inhaltsverzeichnis 1 2 Einleitung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.1 Für wen dieses Buch bestimmt ist . . . . . . . . . . . . . . . . . . . . . . 1 2 1.2 1.3 3 5 Organisation des Buches . . . . . . . . . . . . . . . . . . . . . . . . . . . Web-Site zum Buch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Überblick und Installation . . . . . . . . . . . . 2.1 Was ist Ruby on Rails? . . . . . . . . . . . . 2.2 Bestandteile von Rails . . . . . . . . . . . . 2.2.1 Komponenten und Zusammenspiel 2.2.2 Action Pack . . . . . . . . . . . . . . 2.2.3 Active Record . . . . . . . . . . . . . 2.2.4 Action Mailer . . . . . . . . . . . . . 2.2.5 Ajax . . . . . . . . . . . . . . . . . . 2.2.6 Web Services . . . . . . . . . . . . . 2.2.7 Unit Tests . . . . . . . . . . . . . . . 2.3 Installation . . . . . . . . . . . . . . . . . . . 2.3.1 Windows . . . . . . . . . . . . . . . . 2.3.2 2.3.3 2.3.4 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 7 10 10 11 12 12 12 12 13 13 13 Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 Mac OS X . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 Glückwunsch! Willkommen an Bord! . . . . . . . . . . . . . . . 15 Hands-on Rails . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 3.1 Entwicklungsphilosophie . . . . . . . . . . . . . . . . . . . . . . . . . . 18 3.2 Domain-Modell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 3.3 3.4 3.5 OnTrack Product Backlog . . . . . . . . . . . . . . . . . . . . . . . . . . 19 Aufsetzen der Infrastruktur . . . . . . . . . . . . . . . . . . . . . . . . . 20 Projekte erfassen, bearbeiten und löschen . . . . . . . . . . . . . . . . . 21 3.5.1 3.5.2 Modell erzeugen . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 Datenbankmigration . . . . . . . . . . . . . . . . . . . . . . . . . 22 VIII 4 Inhaltsverzeichnis 3.6 3.7 3.8 3.9 3.10 3.11 3.12 3.13 3.5.3 Controller erzeugen . . . . . . . Iterationen hinzufügen . . . . . . . . . . Zwischenstand . . . . . . . . . . . . . . Iterationen anzeigen . . . . . . . . . . . Iterationen bearbeiten und löschen . . . Tasks hinzufügen . . . . . . . . . . . . . Tasks anzeigen, bearbeiten und löschen Struktur in die Seiten bringen . . . . . . Validierung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 29 36 36 38 40 44 46 47 3.14 3.15 3.16 3.17 Benutzerverwaltung . . Login . . . . . . . . . . . Tasks zuweisen . . . . . Endstand und Ausblick . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51 52 55 57 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Active Record . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 4.1 Active Record-Klassen . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 4.1.1 Mehr über Modellattribute . . . . . . . . . . . . . . . . . . . . . 61 4.5 4.1.2 Mehr über Primärschlüssel . . . . . . . . . . 4.1.3 Mehr über Tabellennamen . . . . . . . . . . . Active Record direkt verwenden . . . . . . . . . . . Objekte erzeugen, laden, aktualisieren und löschen 4.3.1 Erzeugung . . . . . . . . . . . . . . . . . . . . 4.3.2 Objekte laden . . . . . . . . . . . . . . . . . . 4.3.3 Objekte aktualisieren . . . . . . . . . . . . . . 4.3.4 Objekte löschen . . . . . . . . . . . . . . . . . Mehr über Finder . . . . . . . . . . . . . . . . . . . . 4.4.1 Suchbedingungen: conditions . . . . . . . . . 4.4.2 Ordnung schaffen: order . . . . . . . . . . . . 4.4.3 Limitieren: limit . . . . . . . . . . . . . . . . . 4.4.4 Seitenweise: limit und offset . . . . . . . . . . 4.4.5 Weitere Parameter: joins und include . . . . Dynamische Finder . . . . . . . . . . . . . . . . . . . 4.6 4.7 Kann ich weiterhin SQL verwenden? . . . . . . . . . . . . . . . . . . . . 73 Metadaten – Daten über Daten . . . . . . . . . . . . . . . . . . . . . . . 75 4.8 Assoziationen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76 4.2 4.3 4.4 4.8.1 4.8.2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62 63 64 65 66 67 67 69 70 70 71 71 71 72 73 Grundsätzliches . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76 1:1-Beziehungen: has one – belongs to . . . . . . . . . . . . . . . 78 Inhaltsverzeichnis IX 4.8.3 4.8.4 4.8.5 1:N-Beziehungen: has many – belongs to . . . . . . . N:M-Beziehungen: has and belongs to many . . . . Polymorphe Assoziationen: has many – belongs to . 4.8.6 has many :through . . . . . . . . . . . . . . . . . . . . 4.9 Aggregation . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.10 Vererbung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.11 Transaktionen . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.12 Von Bäumen und Listen . . 4.12.1 acts as list() . . . . . 4.12.2 acts as tree() . . . . . 4.13 Validierung . . . . . . . . . 5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84 90 94 97 99 100 103 . . . . . . . . . . . . . . . . . . . . . . . . . 106 . . . . . . . . . . . . . . . . . . . . . . . . . 106 . . . . . . . . . . . . . . . . . . . . . . . . . 108 . . . . . . . . . . . . . . . . . . . . . . . . . 110 4.13.1 Validierungs-Klassenmethoden . . . . . 4.14 Callbacks . . . . . . . . . . . . . . . . . . . . . . 4.14.1 Überschreiben von Callback-Methoden 4.14.2 Callback-Makros . . . . . . . . . . . . . 4.14.3 Observer . . . . . . . . . . . . . . . . . . 4.15 Konkurrierende Zugriffe und Locking . . . . . 4.15.1 Optimistisches Locking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111 115 116 116 118 119 119 Action Controller . . . . . . 5.1 Controller-Grundlagen 5.1.1 Actions . . . . . 5.1.2 Responses . . . 5.2 Datenaustausch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121 121 122 123 126 5.2.1 5.2.2 5.3 5.4 5.5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Vom Controller zum View . . . . . . . . . . . . . . . . . . . . . . 126 Vom View zum Controller . . . . . . . . . . . . . . . . . . . . . . 127 5.2.3 Aus der Action in den View und zurück . . Redirects . . . . . . . . . . . . . . . . . . . . . . . . 5.3.1 Weitere Parameter von redirect to() . . . . Unterschiedliche Response-Formate: respond to() Sessions . . . . . . . . . . . . . . . . . . . . . . . . . 5.5.1 Session-Daten löschen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129 129 130 131 133 134 5.6 5.5.2 Session und Modelle . . . . . . . . . . . . . . . . . . . . . . . . . 134 5.5.3 Session-Optionen . . . . . . . . . . . . . . . . . . . . . . . . . . . 135 Der Flash-Speicher . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136 5.7 5.6.1 Weitere Flash-Methoden . . . . . . . . . . . . . . . . . . . . . . . 137 Filter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137 X Inhaltsverzeichnis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139 139 140 141 141 142 142 145 146 5.9.1 Automatische Layoutzuweisung . . . . 5.9.2 Explizite Layoutzuweisung . . . . . . . 5.9.3 Dynamische Bestimmung des Layouts . 5.9.4 Action-spezifische Layouts . . . . . . . 5.10 Datei-Downloads . . . . . . . . . . . . . . . . . 5.10.1 Die Methode send data() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147 148 149 149 150 5.8 5.9 5.7.1 Around-Filter . . . . . . . . . 5.7.2 Bedingungen . . . . . . . . . 5.7.3 Filterklassen und Inline-Filter 5.7.4 Filtervererbung . . . . . . . . 5.7.5 Filterketten . . . . . . . . . . Routing und URL-Generierung . . . 5.8.1 Routing . . . . . . . . . . . . 5.8.2 URL-Generierung . . . . . . . Layout . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150 5.10.2 Die Methode send file() . . . . . . . . . . . . . . . . . . . . . . . 150 6 Action View . . . . . . . . . . . . . . . . . . . . . . . . . 6.1 HTML-Templates . . . . . . . . . . . . . . . . . . . 6.2 Helper-Module . . . . . . . . . . . . . . . . . . . . 6.3 Action View Helper . . . . . . . . . . . . . . . . . . 6.3.1 Formulare . . . . . . . . . . . . . . . . . . . 6.3.2 Formular-Helper mit Bezug zu Modellen . 6.3.3 Formular-Helper ohne Bezug zu Modellen 6.3.4 HTML-Tags . . . . . . . . . . . . . . . . . . 6.3.5 Texte und Zahlen . . . . . . . . . . . . . . . 6.3.6 Datum und Zeit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153 153 155 156 157 158 160 161 162 163 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163 165 167 168 168 169 169 6.4 6.3.7 Auswahlboxen . . . . . . . . . . . . . . 6.3.8 Verweise und URLs . . . . . . . . . . . 6.3.9 Ressourcen einbinden . . . . . . . . . . 6.3.10 JavaScript . . . . . . . . . . . . . . . . . 6.3.11 Code speichern und wiederverwenden 6.3.12 Debugging . . . . . . . . . . . . . . . . . Layouts . . . . . . . . . . . . . . . . . . . . . . . 6.5 Partial Views – ein View aus Teilen . . . . . . . . . . . . . . . . . . . . . 170 6.6 6.7 Components – Funktionalität wieder verwenden . . . . . . . . . . . . . 172 Pagination – seitenweise blättern . . . . . . . . . . . . . . . . . . . . . . 174 Inhaltsverzeichnis 6.8 6.9 7 XI Anzeige Fehlermeldungen . . . . . . . . . . . . . . . . . . . . . . . . . . 176 XML-Templates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177 Internationalisierung . . . . . . . . . . . . . . 7.1 Internationalisierung oder Lokalisierung? 7.2 Lokalisierung und Codes . . . . . . . . . . 7.2.1 Language Tag . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179 179 180 180 7.3 7.2.2 Locale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180 Checkliste . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181 7.4 7.5 Internationalisierung vorbereiten . . . . . . . . . . . . . . . . . . . . . . 181 Ruby Gettext-Package . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184 7.5.1 7.5.2 7.5.3 7.6 7.7 7.8 Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184 Texte übersetzen . . . . . . . . . . . . . . . . . . . . . . . . . . . 184 Die Schritte im Überblick . . . . . . . . . . . . . . . . . . . . . . 189 7.5.4 Anwendung und Gettext zusammenbringen 7.5.5 Lokalisierte Templates . . . . . . . . . . . . . 7.5.6 Controller . . . . . . . . . . . . . . . . . . . . 7.5.7 Modelle . . . . . . . . . . . . . . . . . . . . . 7.5.8 Dynamische Texte und Pluralisierung . . . . 7.5.9 Datum, Zahlen und Währungen . . . . . . . 7.5.10 Wochen- und Monatsnamen . . . . . . . . . 7.5.11 Sortierung . . . . . . . . . . . . . . . . . . . . 7.5.12 Zusammenfassung . . . . . . . . . . . . . . . Globalize . . . . . . . . . . . . . . . . . . . . . . . . . 7.6.1 Vorbereitung und Installation . . . . . . . . . 7.6.2 Übersetzungen einpflegen . . . . . . . . . . . 7.6.3 Lokalisierte Templates . . . . . . . . . . . . . 7.6.4 Controller . . . . . . . . . . . . . . . . . . . . 7.6.5 Modelle . . . . . . . . . . . . . . . . . . . . . 7.6.6 Dynamische Texte und Pluralisierung . . . . 7.6.7 Datum, Zahlen und Währungen . . . . . . . 7.6.8 Wochen- und Monatsnamen . . . . . . . . . 7.6.9 Sortierung . . . . . . . . . . . . . . . . . . . . 7.6.10 Zusammenfassung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189 191 191 191 193 195 196 198 198 199 199 201 203 204 204 206 206 208 208 208 Gettext oder Globalize . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208 Weitere Bibliotheken . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209 7.8.1 GLoc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209 XII Inhaltsverzeichnis 7.8.2 8 Action Mailer . . . . . . . . . . . . . 8.1 E-Mail-Versand . . . . . . . . . 8.1.1 E-Mail erstellen . . . . . 8.1.2 E-Mail-Objekt erzeugen 8.1.3 E-Mail versenden . . . . 8.1.4 8.1.5 8.2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211 211 211 214 215 Testen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216 Multipart E-Mails . . . . . . . . . . . . . . . . . . . . . . . . . . . 218 E-Mail-Empfang . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220 8.2.1 E-Mail empfangen . . . . . . . . . . . . . . . . . . . . . . . . . . 221 8.2.2 9 ICU4R . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210 Empfang testen . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222 Web Services . . . . . . . . . . . . . . . 9.1 Web Service-Grundlagen . . . . . . 9.2 Web Service Interfaces . . . . . . . 9.2.1 Die Methode api method() 9.2.2 Parameter-Typen . . . . . . 9.2.3 Parameter-Formate . . . . . 9.3 Web Service-Implementierung . . 9.3.1 Direct Dispatching . . . . . 9.3.2 Layered Dispatching . . . . 9.3.3 Delegated Dispatching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225 225 226 226 227 228 228 229 230 231 9.4 9.5 Generatoren . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232 Testen von Web Services . . . . . . . . . . . . . . . . . . . . . . . . . . . 232 9.6 9.7 Filter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233 Web Service Clients . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234 9.8 9.7.1 Umstellung auf ActionWebService::Struct . . . . . . . . . . . . . 234 9.7.2 Ein SOAP-Client für den Ontrack-Service . . . . . . . . . . . . . 235 WSDL-Generierung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 236 10 Web 2.0 – Ajax und Co. . . . . 10.1 Ajax . . . . . . . . . . . . . 10.1.1 Ajax und Rails . . . 10.1.2 Hello, Ajax World . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237 237 239 240 10.1.3 Ajax-Formulare . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241 10.1.4 Feldbeobachter . . . . . . . . . . . . . . . . . . . . . . . . . . . . 244 10.1.5 Callback-Methoden . . . . . . . . . . . . . . . . . . . . . . . . . . 247 Inhaltsverzeichnis XIII 10.1.6 Drag and Drop . . . . . . . . . . . . . . . . . . . 10.1.7 Autocompletion . . . . . . . . . . . . . . . . . . . 10.1.8 Automatisches Aktualisieren . . . . . . . . . . . 10.2 Effekte – Visuelles Feedback für den Anwender . . . . 10.2.1 Elemente ein- und ausblenden . . . . . . . . . . 10.2.2 Dem Anwender zeigen, dass der Server arbeitet 10.2.3 Weitere Effekte . . . . . . . . . . . . . . . . . . . 10.3 RJS Templates . . . . . . . . . . . . . . . . . . . . . . . . 10.3.1 Hinzufügen von Tasks visuell optimieren . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 248 254 254 255 255 256 257 257 258 10.3.2 Weitere Techniken . . . . . . . . . . . . . . . . . . . . . . . . . . 261 10.3.3 Debugging und Testen . . . . . . . . . . . . . . . . . . . . . . . . 264 10.4 Zusammenfassung und Ausblick . . . . . . . . . . . . . . . . . . . . . . 265 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 267 267 267 268 11.1.3 Unsichere Dateidownloads . . . . . 11.1.4 Direkteingabe einer URL mit ID . . Debugging . . . . . . . . . . . . . . . . . . . Active Record-Tipps . . . . . . . . . . . . . 11.3.1 Legacy-Datenbanken . . . . . . . . . 11.3.2 Modelle ans Schema anpassen . . . 11.3.3 Verwendung von Views . . . . . . . 11.3.4 Andersnamige Primärschlüssel . . . 11.3.5 Zusammengesetzte Schlüssel . . . . 11.3.6 Case-sensitive Strings . . . . . . . . Vermeiden von doppelten Logins . . . . . . GET oder POST? . . . . . . . . . . . . . . . Performance und Skalierbarkeit . . . . . . . 11.6.1 Caching . . . . . . . . . . . . . . . . 11.6.2 Skalierung von Rails-Anwendungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 269 270 270 271 271 271 272 272 272 273 273 274 275 275 280 11 Web-Entwicklung mit Rails in der Praxis 11.1 Sicherheit . . . . . . . . . . . . . . . . 11.1.1 SQL-Injection . . . . . . . . . 11.1.2 Batch-Update von Modellen 11.2 11.3 11.4 11.5 11.6 . . . . . . . . . . . . 11.7 Datei-Up- und -Downloads . . . . . . . . . . . . . . . . . . . . . . . . . 282 11.7.1 Ein Modell für Dateianhänge . . . . . . . . . . . . . . . . . . . . 283 11.7.2 Ein View zum Upload von Dateien . . . . . . . . . . . . . . . . . 284 11.7.3 Eine Controller-Action zum Speichern von Dateien . . . . . . . 284 11.7.4 Ein View zum Download von Dateianhängen . . . . . . . . . . 286 XIV Inhaltsverzeichnis 11.8 Fehlermeldungen sortieren . . . . . . . . . . . . . . . . . . . . . . . . . 286 12 Die Anwendung in Produktion bringen 12.1 Umgebungen in Rails . . . . . . . . . 12.1.1 Umgebung definieren . . . . 12.1.2 Entwicklung . . . . . . . . . . 12.1.3 Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291 291 291 292 292 12.1.4 Produktion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 293 12.2 Datenbank und Webserver . . . . . . . . . . . . . . . . . . . . . . . . . . 294 12.2.1 WEBrick . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 294 12.2.2 Apache und CGI . . . . . . . . . . . . . . . . . . . . . . . . . . . 294 12.2.3 Apache und FastCGI . . . . . . . . . . . . . . . . . . . . . . . . . 295 12.2.4 Apache und Mongrel . . . . . . . . . . . . . . . . . . . . . . . . . 296 12.2.5 LightTPD und FastCGI . . . . . . . . . . . . . . . . . . . . . . . 297 12.2.6 SCGI – Alternative zu FastCGI 12.3 Anwendung ausliefern . . . . . . . . . 12.4 Anwendung warten . . . . . . . . . . 12.4.1 Wartung . . . . . . . . . . . . . 12.4.2 Monitoring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 298 298 298 299 300 13 Deployment mit Capistrano (und Subversion) . . . 13.1 Quickstart: Capistrano in 10 Minuten . . . . . 13.1.1 Voraussetzungen . . . . . . . . . . . . . 13.1.2 Installation von Capistrano . . . . . . . 13.1.3 Anwendung Capistrano-ready machen 13.1.4 Konfiguration . . . . . . . . . . . . . . . 13.1.5 Setup des entfernten Verzeichnisses . . 13.1.6 Erstes Deployment . . . . . . . . . . . . 13.1.7 Fallstricke . . . . . . . . . . . . . . . . . 13.1.8 Nachfolgende Deployments . . . . . . . 13.2 Datenbanksetup und Migration . . . . . . . . . 13.3 Rollback eines Release . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 303 304 304 306 306 307 309 309 311 312 313 314 13.3.1 Rollback mit Datenbankmigration . . . . . . . . . . . . . . . . . 314 13.4 Tasks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 314 13.4.1 Ausführen von Tasks . . . . . . . . . . . . . . . . . . . . . . . . . 315 13.4.2 Mehr über run und sudo . . . . . . . . . . . . . . . . . . . . . . . 316 13.4.3 Weitere Task-Helper: delete, put und render . . . . . . . . . . . 317 13.4.4 Transaktionen und Rollbacks . . . . . . . . . . . . . . . . . . . . 317 Inhaltsverzeichnis 13.5 13.6 13.7 13.8 XV 13.4.5 Überschreiben von Standardtasks . . . . . . 13.4.6 Tasks erweitern: Before- und After-Tasks . . Variablen . . . . . . . . . . . . . . . . . . . . . . . . . FastCGI-Utilities . . . . . . . . . . . . . . . . . . . . . 13.6.1 Spawner . . . . . . . . . . . . . . . . . . . . . 13.6.2 Reaper . . . . . . . . . . . . . . . . . . . . . . Gemeinsame Dateien – das Shared-Verzeichnis . . . 13.7.1 Eine persistente“ Datenbank-Konfiguration ” Capistrano-Referenz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 318 318 319 320 320 321 321 321 323 13.9 Capistrano-Konfiguration: deploy.rb . . . . . . . . . . . . . . . . . . . . 324 14 Testgetriebene Entwicklung mit Ruby und Test::Unit . . . . . . . . . . . . 325 14.1 Unit Tests – eine Definition . . . . . . . . . . . . . . . . . . . . . . . . . 325 14.2 Ein Beispiel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 326 14.3 Warum testen? . . . . . . . . . . . . . . 14.4 Test::Unit . . . . . . . . . . . . . . . . . 14.4.1 Strukturierung von Unit Tests . 14.4.2 Wohin mit den Tests? . . . . . . 14.4.3 Ausführen der Tests . . . . . . 14.4.4 Unabhängigkeit von Tests . . . 14.5 Testgetriebene Softwareentwicklung . 14.5.1 TODO-Listen . . . . . . . . . . 14.5.2 Beispiel . . . . . . . . . . . . . . 14.6 Retrospektive . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 327 328 329 331 331 332 333 334 335 336 15 Testgetriebene Entwicklung mit Ruby on Rails 15.1 Generierte Testklassen . . . . . . . . . . . . 15.2 Testdatenbank . . . . . . . . . . . . . . . . . 15.3 Testausführung über Rake . . . . . . . . . . 15.4 Eine Programmierepisode . . . . . . . . . . 15.4.1 Entwicklung einer Modellklasse . . 15.4.2 Entwicklung des Controllers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 337 337 338 339 339 340 344 15.4.3 Anpassung des Views . . . . . . . . . . . . . . . . . . . . . . . . 345 15.4.4 Geänderte Anforderungen . . . . . . . . . . . . . . . . . . . . . 347 15.4.5 Retrospektive . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 353 15.5 Unit Tests – Testen von Modellklassen . . . . . . . . . . . . . . . . . . . 354 15.5.1 Struktur und Elemente von Modelltests . . . . . . . . . . . . . . 354 15.5.2 Testmethoden . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 355 XVI Inhaltsverzeichnis 15.5.3 Testdaten – Fixtures . . . . . . . . . . . . . . . 15.5.4 Transaktionale Fixtures . . . . . . . . . . . . . 15.5.5 Testrezepte für Modelle . . . . . . . . . . . . . 15.6 Funktionale Tests – Testen von Controllern und Views 15.6.1 Struktur und Elemente von Controller-Tests . 15.6.2 Testmethoden . . . . . . . . . . . . . . . . . . . 15.6.3 Kontrollfluss-Assertions . . . . . . . . . . . . . 15.6.4 Routing-Assertions . . . . . . . . . . . . . . . . 15.6.5 Datencontainer-Assertions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 356 358 358 363 364 364 365 367 368 15.6.6 Template-Assertions . . . . . . . . . . 15.6.7 Testrezepte für Controller und Views 15.7 Integrationstests . . . . . . . . . . . . . . . . . 15.7.1 Test-DSLs . . . . . . . . . . . . . . . . 15.7.2 Sessions . . . . . . . . . . . . . . . . . 15.8 Testen von E-Mails und Web Services . . . . 15.9 Mock-Objekte . . . . . . . . . . . . . . . . . . 15.10Zusammenfassung . . . . . . . . . . . . . . . 15.11Assertions – Übersicht . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 369 371 374 376 377 378 378 379 380 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Anhang . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 381 Literaturverzeichnis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 391 Stichwortverzeichnis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 393 Kapitel 4 Active Record Das Active Record-Framework ist eines der drei Sub-Frameworks von Rails. Das Framework stellt die Verbindung zwischen Domain-Objekten und Datenbank her und ermöglicht die komfortable Speicherung von Objekten in der zugrunde liegenden Datenbank. Active Record-Objekte kapseln Daten und Geschäftslogik. Sie beziehen ihre Attribute direkt aus der zugehörigen Datenbanktabelle. Änderungen am Datenmodell haben unmittelbare Auswirkungen auf das Domain-Modell. Duplizierung, d.h. redundante Wiederholung von Informationen, findet nicht statt. 4.1 Active Record-Klassen Active Record basiert auf dem gleichnamigen Pattern (siehe Kasten Active Record – das Pattern) zur Abbildung von Objektmodellen auf relationale Datenbanken. Eine Active Record-Klasse repräsentiert dabei eine Datenbanktabelle und ein Objekt dieser Klasse eine Datenzeile in dieser Tabelle. Active Record-Klassen erben von ActiveRecord::Base: class User < ActiveRecord::Base end Die Verbindung zwischen einer Active Record-Klasse und ihrer zugehörigen Datenbanktabelle stellt Rails über den Namen der Klasse her, indem als Tabellenname die pluralisierte Form des Klassennamens verwendet wird. Objekte der Klasse User werden in der Tabelle users gespeichert: class CreateUsers < ActiveRecord::Migration def self.up create_table :users do |t| t.column :firstname, :string t.column :lastname, :string end 60 4 Active Record end def self.down drop_table :users end end Active Record – das Pattern Dem Active Record-Framework liegt das gleichnamige Pattern Active Record zugrunde, das von Martin Fowler in [7] beschrieben wurde. Zentrale Idee von Active Record ist die Verwendung von Klassen zur Repräsentation einer Datenbanktabelle. Eine Active Record-Klasse korrespondiert dabei mit genau einer Datenbanktabelle. Eine Instanz einer Active Record-Klasse repräsentiert genau eine Datenzeile in dieser Tabelle. Die Felder einer Active Record-Klasse müssen 1:1 mit den Feldern der zugehörigen Tabelle korrespondieren. Während in Java dafür entsprechende Attribute mit Gettern und Settern programmiert werden (DRY-Verletzung, siehe auch Abschnitt 2.1), werden die Attribute von Rails Active Records ausschließlich in der Tabelle definiert (DRY-Einhaltung, siehe auch Abschnitt 2.1). Dank Ruby ist es möglich, Active Record-Klassen zur Laufzeit um Attribute und Zugriffsmethoden für die zugehörigen Tabellenfelder zu erweitern. Active Record-Klassen spezifizieren ihre Attribute nicht direkt, sondern beziehen sie aus der Tabellendefinition der zugehörigen Datenbanktabelle.1 Für jedes Feld der zugehörigen Tabelle erzeugt Active Record eine Getter- und eine Setter-Methode. Beispielsweise wird die Klasse User für das Tabellenfeld lastname um die beiden Methoden lastname() und lastname=() erweitert: user = User.create(:lastname => "Wirdemann") puts "Lastname: " + user.lastname() # der Getter user.lastname = "Baustert" # der Setter Darüber hinaus erzeugt Active Record für jedes Tabellenfeld eine Instanzvariable. Um innerhalb der Modellklasse zwischen Instanzvariable und Getter- und SetterMethoden zu unterscheiden, muss der Instanzvariablen das Schlüsselwort self vorangestellt werden: class User < ActiveRecord::Base def fullname firstname + " " + lastname # Getter self.lastname # Instanzvariable end end 1 Selbstverständlich kann eine Active Record-Klasse neben den aus der Tabelle bezogenen Attributen wei- tere Attribute definieren. 4.1 Active Record-Klassen 61 Überschreiben von Gettern und Settern Dynamisch erzeugte Getter und Setter können überschrieben werden. Um dabei rekursive Aufrufe zu vermeiden, darf der jeweilige Getter bzw. Setter in der überschriebenen Methode nicht verwendet werden. Stattdessen stehen die Methoden write attribute und read attribute bzw. die direkte Nutzung der Hash self zur Verfügung: class User < ActiveRecord::Base def lastname= name write_attribute(:lastname, name) # entweder so, self[:lastname] = name # oder so end def lastname read_attribute(:lastname) self[:lastname] end end 4.1.1 # entweder so, # oder die Hash Mehr über Modellattribute Tabellenfelder definieren die Attribute von Modellklassen. Beim Lesen und Schreiben von Modellinstanzen bildet Active Record die Attribute bzw. Felder auf den korrespondierenden Typ des jeweils anderen Systems ab. Die Abbildung von ein” fachen“ Datentypen2 , wie Strings oder Fixnums, führt Active Record automatisch durch. Komplexere Datentypen wie Arrays, Hashes oder andere serialisierbare Objekte3 werden in Tabellenfeldern vom Typ Text gespeichert. Als Beispiel erweitern wir die Tabelle users um das Feld preferences zum Speichern von speziellen Benutzereinstellungen: class AddPreferencesToUsers < ActiveRecord::Migration def self.up add_column :users, :preferences, :text end def self.down remove_column :users, :preferences end end In der Modellklasse User werden Benutzereinstellungen in einer Hash gespeichert. Für die Konvertierung der Hash in ein Textfeld und umgekehrt muss das Attribut in der Modellklasse explizit als serialisierbar deklariert werden. Diesem Zweck dient die Methode serialize(): class User < ActiveRecord::Base 2 Nicht 3 Im zu verwechseln mit primitiven Datentypen, die es in Ruby nicht gibt. Prinzip alle Objekte, die sich mit Hilfe von YAML serialisieren lassen. 62 4 Active Record serialize :preferences end preferences = {"farbe" => "gruen", "anzahl" => 11} user = User.create(:preferences => preferences) user.reload puts user.preferences.inspect $ {"anzahl"=>11, "farbe"=>"gruen"} Active Record führt das Typ-Mapping automatisch durch. Wenn preferences an Stelle einer Hash mit einem Array initialisiert wird, dann wird beim nächsten Laden des Objekts user ein Array instanziiert: user = User.create(:preferences => %w(blau rot)) user.reload puts user.preferences.inspect $ ["blau", "rot"] Ein optionaler Typ-Parameter von serialize schränkt die möglichen Typen des zu serialisierenden Objekts auf genau einen Typ ein: class User < ActiveRecord::Base serialize :preferences, Hash end In diesem Fall wirft Active Record beim Zugriff auf preferences eine SerializationTypeMismatch-Exception, wenn das Attribut preferences zuvor als Array gespeichert wurde: user = User.create(:preferences => %w(blau rot)) user.reload puts user.preferences.inspect # Exception $ ActiveRecord::SerializationTypeMismatch: preferences was supposed to be a Hash, but was a Array 4.1.2 Mehr über Primärschlüssel Jede Active Record-Tabelle benötigt einen Primärschlüssel. Standardmäßig nimmt Active Record hierfür den Namen id an. Hält man sich an diese Konvention, dann wird die Verwaltung des Primärschlüssels vollständig von Active Record übernommen. Für neue Datensätze wird deren initialer ID-Wert von der Datenbank erzeugt: user = User.new(:firstname => "Ralf") user.save puts user.id $ 1 4.1 Active Record-Klassen 63 Der Primärschlüssel eines Modell kann über die Methode set primary key() explizit angegeben werden. Das folgende Beispiel erweitert die Tabelle users um ein Feld mobile no und macht dieses Feld zum Primärschlüssel des User-Modells: class AddMobileNoToUsers < ActiveRecord::Migration def self.up add_column :users, :mobile_no, :integer end def self.down remove_column :users, :mobile_no end end class User < ActiveRecord::Base set_primary_key :mobile_no end Für den Zugriff auf den Primärschlüssel einer Modellklasse verwendet Active Record intern weiterhin die Getter-Methode id(), d.h. diese Methode steht Ihnen weiterhin zur Verfügung und liefert demzufolge den gleichen Wert wie die GetterMethode des explizit spezifizierten Primärschlüssels: user = User.new(:firstname => "Ralf") user.save puts "Mobile: #{user.mobile_no}" puts "Id : #{user.id}" $ Mobile: 12 Id : 12 4.1.3 Mehr über Tabellennamen Per Konvention erwartet Active Record als Tabellennamen die Pluralform des zugehörigen Modellnamens. Active Record berücksichtigt dabei einige Sonderformen der englischen Sprache, indem z.B. person nach people und nicht nach persons pluralisiert wird. Tabelle 4.1 gibt einen Überblick über mögliche Kombinationen. Tabelle 4.1: Abbildung von Modellnamen auf Tabellennamen Modellklasse Tabellenname Project User Person Child Tasks Projekt Benutzer projects users people children tasks projekts benutzers Stichwortverzeichnis :complete 248 :conditions 70 :dependent 81, 87 :include 72 :interactive 247 :joins 72 :limit 71 :loaded 247 :loading 247 :offset 71 :order 71 :polymorphic 96 :through 97 1:1-Beziehungen 78 1:N-Beziehungen 84 404.html 293 Action Controller 121 Actions 122 after filter() 138 around filter() 139 Base 121 Base.fragment cache store 280 Base.perform caching 275 Base.template root() 124 before filter() 138 Caching::Fragments 280 Caching::Sweeper 277 CgiRequest::DEFAULT SESSION OPTIONS 135 Datei-Downloads 150 Datenaustausch 126 DoubleRenderError 126 Filter 137 Filterklassen 140 flash() 136 Flash-Speicher 136 Generator 121 hide action() 123 Inline-Filter 140 Instanzvariablen 126 layout() 148 Layouts 146 Mehrdimensionale Parameter 128 params 127 prepend after filter() 141 prepend before filter() 141 private Methoden 123 process() 144 protected Methoden 123 redirect to() 130 Redirects 129 Reflection 122 render() 124 Request Parameter 127 reset session() 134 Responses 123 Routing 142 send data() 150 send file() 150 session() 133 Session-Optionen 135 URL-Generierung 145 URL-Parameter 122 url for() 146 View-Verzeichnis 124 Action Mailer 211 attachment, Methode 220 394 Base.implicit parts order 220 Base.server settings 215, 216 Base64 219 create XXX 214 deliver XXX 214 Fehler beim Versand 216 Fixture 217 Helper Modul 213 Kopfdaten einer E-Mail 212 Mail, eingehende verarbeiten 221 Multipart explizit 218 Multipart implizit 220 Multipart Mails 218 part, Methode 219 PDF versenden 218 POP3, Abruf von 221 receive, Methode 221 Sendmail, Versand über 215 SMTP, Versand über 214, 215 Template-Verzeichnis 220 Templates 212 Test, Empfang einer E-Mail 222 Test, Versand einer Mail 216 Testumgebung 217 TMail 214 Versand einer E-Mail 211 Action View 153 Anzeige Validierungsfehler 176 application.rhtml 169 ApplicationHelper 156 Auswahlboxen 163 auto link() 162 Blättern 174 button to() 166 capture() 168 check box() 159 Components 172 content for() 168 content tag() 161 date select() 163 Debugging 169 end form tag() 157 error message on() 176 error messages for() 176 file field() 160 form for() 157 Stichwortverzeichnis form tag() 157 FormHelper 159 Formular 158 Helper-Modul 155 hidden field() 160 HTML-Formular 158 HTML-Template 153 human size() 162 image tag() 167 Instanzvariablen 154, 170 javascript include tag() 167 Layouts 169 link to() 165 mail to() 166 number with delimiter() 162 options for select() 164 options from collection for select() 165 paginate() 174 pagination links() 175 PaginationHelper 175 Paginator 174 Partials View 170 password field tag() 161 radio button tag() 161 render component 172 render component as string() 173 select() 164 select tag() 161 start form tag() 157 strip links() 162 stylesheet link tag() 167 tag() 161 Template, HTML 153 Template, XML 177 text area() 159 text field() 158 text field tag() 160 truncate() 162 Upload von Dateien 160 Versteckte Felder 160 View 153 XML-Template 177 Actions 122 ActionView::Helpers::JavaScriptHelper 239 Stichwortverzeichnis Finder 70 ActionWebService::Client::Soap 234 Fremdschlüssel 76 ActionWebService::Client::XmlRpc 234 has and belongs to many() 90 ActionWebService::Struct 227, 234 ActionWebServiceAPI::Base 226 has many() 76, 85 Active Record 59 has one() 78 1:1-Beziehungen 78 Komplexe Modellattribute 61 1:N-Beziehungen 84 Konkurrierende Zugriffe 119 acts as list() 106 Konstruktor 66 Locking 119 acts as tree() 108 Metadaten 75 after create() 116 N:M-Beziehungen 90 after find() 116 Objekte erzeugen 66 after initialize() 116 Objekte löschen 69 after save() 116 Objekte laden 67 after update() 116 observe() 119 after validation() 116 Observer 118 after validation on create() 116 Pattern 60 after validation on update() 116 Primärschlüssel 62 Assoziationen 76 reload() 67 Attribute 60 save() 66, 67 Base.pluralize table names() 272 save with validation() 110 before create() 116 before save() 116 self 60 set primary key() 63 before update() 116 before validation() 116 set table name() 64 before validation on create() 116 Transaktionen 103 before validation on update() 116 update() 68 belongs to() 77, 82, 88 update all() 69 Callbacks 69, 115 update attribute() 68 Aufrufreihenfolge 115 update attributes() 68 column names() 75 validate() 110 validate on create() 111 columns() 75 validate on update() 111 content columns() 75 create() 66 validates acceptance of() 112 delete() 69 validates associated() 112 delete all() 69 validates confirmation of() 113 destroy() 69 validates each() 113 destroy all() 69 validates exclusion of() 113 deutsche Modell- und Tabellennamen validates format of() 113 64 validates inclusion of() 114 direkt verwenden 64 validates length of() 114 errors() 110 validates numericality of() 115 establish connection() 65 validates presence of() 111 find() 67 validates uniqueness of() 115 find all by() 73 Validierung 110 Vererbung 100 find by() 73 acts as list() 106 find by sql() 74 395 396 :order 107 position 106 acts as tree() 108 :foreign key 109 :order 109 parent id 108 after create() 116 after filter() 138 after find() 116 after initialize() 116 after invocation() 233 after save() 116, 117 after update() 116 after validation() 116 after validation on create() 116 after validation on update() 116 Aggregation 99 composed of() 99 Ajax 237 application.js 240 auto complete for() 254 auto complete responder for() 254 Autocompletion 254 Callback-Methoden 247 :complete 248 :interactive 247 :loaded 247 :loading 247 controls.js 240 Debugging 264 dragdrop.js 240, 248 draggable element() 248 drop receiving element() drop receiving element() 248 Dynamische Suchlisten 244 Effect.Appear() 389 Effect.BlindDown() 389 Effect.BlindUp() 389 Effect.DropOut() 389 Effect.Fade() 389 Effect.Fold() 389 Effect.Grow() 389 Effect.Highlight() 390 Effect.Puff() 390 Effect.Pulsate() 390 Effect.Scale() 390 Stichwortverzeichnis Effect.Shake() 390 Effect.Shrink() 390 Effect.SlideDown() 390 Effect.SlideUp() 390 Effect.Squish() 390 Effect.SwitchOff() 389 Effect.toggle() 389 effects.js 240, 257 Effekte 255 Element.hide() 256 Element.remove() 256 Element.show() 256 Element.toggle() 256 FireBug 264 form remote tag() 241, 243 JavaScript 244 JavaScriptGenerator 259 observe field() 244 page-Objekt 259 Partial-Views für Listen 242 periodically call remote() 254 Prototype 239 prototype.js 239 render rjs 258 RJS Class Proxy 262 RJS Collection Proxy 263 RJS Element Proxy 263 RJS im Controller 261 RJS Templates 257 RJS und Helper-Methoden 262 RJS und Redirect 261 Task-Schnellerfassung 242 Testen 264 Testen mit ARTS 265 text field with auto complete() 254 und Rails 239 update page() 259 visual effect 260 Ajax-Engine 238 Akzeptanztests 376 Anwendung ausliefern 298 Anwendung warten 298 Apache und CGI 294 Apache und FastCGI 295 api method() 226 :expects 226 Stichwortverzeichnis :returns 227 application.js 240 application.rhtml 169 ApplicationHelper-Modul 156 around filter() 139 assert raise() 363 assert tag() 346 Assertions – Übersicht 380 assigns 346 Assoziationen 76 attr accessible() 269 attr protected() 269 Auswahlboxen 163 auto complete for() 254 auto complete responder for() 254 auto increment 62 auto link() 162 Autocompletion 254 Bäume 106 Backup 299 Batch-Updates 268 absichern 269 before create() 116 before destroy() 117 before filter() 138 :except 139 :only 139 before invocation() 233 before save() 116 before update() 116 before validation() 116 before validation on create() 116 before validation on update() 116 belongs to() 31, 77 :class name 83 :conditions 83 :counter cache 83, 88 :foreign key 83 :order 83, 88 :polymorphic 96 Unterschied zu has one() 83 Blättern 174 breakpoint() 270 breakpointer (Skript) 270 button to() 166, 274 397 cache() 278 cache sweeper() 278 caches action() 276 caches page() 276 Caching 275 ActionController::Base.fragment cache store 280 ActionController::Caching::Fragments 280 cache() 278 cache sweeper() 278 caches action() 276 caches page() 276 expire action() 276 expire fragment() 279 expire page() 276 read fragment() 278 Statischer Seitenbereich 278 Sweeper 277 Callback-Makros 116 Callback-Objekte 117 Callbacks 115 Überschreiben 116 Capistrano 303 :application 323 :deploy to 308 :repository 307 :svn 312 :use sudo 308 :user 308 After-Tasks 318 Before-Tasks 318 Datenbankmigration 313 delete() 317 deploy.rb 307 Fallstricke 311 FastCGI-Prozesse starten 309 Installation 306 Konfiguration 307 LightTPD konfigurieren 310 LightTPD starten 310 on rollback 318 put() 317 Quickstart 304 Reaper 321 Referenz 323 398 remote:cold deploy 310 remote:deploy 312 remote:deploy with migrations 314 remote:exec 315 remote:migrate 313 remote:rollback 314 remote:setup 309 render() 317 Rollback 314 Rollen 307 run() 315, 316 Setup 309 Shared Verzeichnis 321 spawn-fcgi 312 Spawner 309, 320 Spinner-Task 309 Standardtasks überschreiben 318 Subversion 305 sudo() 315, 316 Tasks 314 Tasks ausführen 315 Tasks und Rollen 315 Transaktionen 317 Variablen 319 capture() 168, 288 CGI::Session::ActiveRecordStore 136 check box() 159 collection select() 56 column names() 75 columns() 75 Components 172 composed of() 99 connect() 142 consider all requests local 293 Console-Skript 300 Constraint 25 content columns() 75 content for() 168 content tag() 161 Controller 121 testen 344 Controller-Test get() 344 HTTP-Requesttypen 344 controls.js 240 create() 66 Stichwortverzeichnis CRUD 27, 65 curl 132 date select() 163 Datei-Downloads 150 Datenbank-Constraint 25 Datenbankkonfiguration 20 Datenbankmigration 382 add column() 383 add index() 384 Capistrano 313 change column() 384 change column default() 384 create table(name, options) 382 drop table(name) 383 Generator 26, 382 IrreversibleMigration 385 Migrationsskript ausführen 382 Migrationsskript erzeugen 382 remove column() 383 remove index() 384 rename column() 383 rename table() 383 SQL ausführen 384 Debugging 270 Ausgabe von Objekten im View 169 DEFAULT SESSION OPTIONS 281 delete() 69 delete all() 69 deploy.rb 307, 324 Deployment 291 404.html 293 Anwendung ausliefern 298 Anwendung warten 298 Apache und CGI 294 Apache und FastCGI 295 Apache und Mongrel 296 Backup 299 Capistrano 303 consider all requests local 293 Console-Skript 300 E-Mail, Versand bei Ausnahme 301 Entwicklungsumgebung 292 environment.rb 291 FastCGI Ruby Binding 295 FastCGI-Dispatcher 295 Stichwortverzeichnis httpd.conf 294 Installierte Komponenten 294 LightTPD und FastCGI 297 local request?() 293 Log-Dateien 299 mod fastcgi.so 295 Monitoring 300 OnTrack 294 perform caching 293 Produktionsumgebung 293 RAILS ENV 291 rescue action in public() 293 SCGI 298 Sessions aufräumen 299 Testumgebung 292 Timeout 295 Umgebung definieren 291 WEBrick 294 destroy() 69 destroy all() 69 Direkteingabe einer URL mit ID 270 DOM 238 Domain-Modell 18 Doppelte Logins 273 DoubleRenderError 126, 131 Drag and Drop 248 acts as list() 252 Beispiel 249 has many() 252 Sortieren 251 dragdrop.js 240 draggable element() 248 :revert 248 DRY 8 DSL 376 Dynamische Finder 73 E-Mail, Versand bei Ausnahme 301 Effect.Appear() 389 Effect.BlindDown() 389 Effect.BlindUp() 389 Effect.DropOut() 389 Effect.Fade() 389 Effect.Fold() 389 Effect.Grow() 389 Effect.Highlight() 390 399 Effect.Puff() 390 Effect.Pulsate() 390 Effect.Scale() 390 Effect.Shake() 390 Effect.Shrink() 390 Effect.SlideDown() 390 Effect.SlideUp() 390 Effect.Squish() 390 Effect.SwitchOff() 389 Effect.toggle() 389 effects.js 240 Element.hide() 256 Element.remove() 256 Element.show() 256 Element.toggle() 256 end form tag() 157 Entwicklungsumgebung 292 environment.rb 291 ERb 126 error message on() 176 error messages for() 176, 286 errors() 110 on() 111 establish connection() 65 expire action() 276 expire fragment() 279 expire page() 276 FastCGI Ruby Binding 295 FastCGI-Dispatcher 295 Feedback 18 Fehlermeldungen sortieren 286 capture() 288 error messages for() 286 fieldWithErrors 287 show with errors() 288 fieldWithErrors 287 file field() 160 Filter 137 Ausführungskette 138 Bedingungen 139 before filter() 53 Filterketten 141 Vererbung 141 filter() 140 Filterketten 141 400 Filterklassen 140 find() 67 :all 67 :conditions 70 :first 67 :include 72 :joins 72 :limit 71 :offset 71 :order 71 asc 71 desc 71 find all by() 73 find by() 73 find by sql() 74 Fixtures 342, 356 Verzeichnis 356 Verzeichnisse 338 fixtures() 356 Flash Speicher 136 Redirects 136 flash() 136 keep() 137 now() 137 form for() 157 form remote tag() 241, 243 :complete 257 :loading 257 :position 243 :update 241 :url 241 form tag() 33, 157 FormHelper 159 Formular 158 Fragment-Caching 278 Fremdschlüssel 30, 76 Funktionale Tests 363 Generator 22 GET-Request 274 Gettext 184 has and belongs to many() :association foreign key 93 :class name 92 :conditions 93 :delete sql 94 Stichwortverzeichnis :finder sql 94 :foreign key 93 :insert sql 94 :join table 93 :order 93 :unique 94 erzeugte Methoden 91 has many() 35, 76, 85 :as 96 :counter sql 87 :dependent 87 :finder sql 87 :through 97 has one() 78 :class name 79 :conditions 80 :dependent 81 :foreign key 81 :order 80 Unterschied zu belongs to() 83 Helper-Modul 155 hidden field() 160 HTML-Formular 158 HTML-Template 153 HTTP Accept 131 httpd.conf 294 human size() 162 Iconv 182 image tag() 167 Inline-Filter 140 InnoDB 103, 358 Installation Capistrano 306 Instant Rails 13 Locomotive 15 One-Click Ruby Installer 13 unter Linux 14 unter Mac OS X 15 unter Windows 13 Installierte Komponenten 294 Instant Rails 13 Instanzvariablen im Layout 170 im View 154 Stichwortverzeichnis Integrationstests 374 Sessions 377 Internationalisierung 179 $KCODE 183 Anwendung vorbereiten 181 Bibliothek jcode 183 Checkliste 181 Datenbank und Zeichensatz 182 Gettext Controller 191 Datum, Zahlen, Währungen 195 Datumsfelder 196 Dynamische Texte 193 Fehlermeldungen 192, 205 init gettext() 189 Lokalisierte Templates 191 Methode () 185 Methode gettext() 185 mo-Datei 185 Modelle übersetzen 191 Monate 196 Pluralisierung 194 po-Datei 185 pot-Datei 184 Rake-Task 186 Sortierung 198 Wochentage 196 Globalize 199 Übersetzungen einpflegen 201 Arbeitsweise und Probleme 203 Controller 204 Datum, Zahlen und Währungen 206 Lokalisierte Templates 203 Modelle 204 Plugin einbinden 200 Reihenfolge dynamischer Werte 206 Sortierung 208 Wochen- und Monatsnamen 208 GLoc 209 GNU Gettext 184 HTML und Zeichensatz 183 Iconv 182 ICU4R 210 Response-Header und Zeichensatz 183 Ri18n 209 Ruby-Gettext-Package 184 401 UTF-8 181 Irb 271 javascript include tag() 167 keep() 137 Konfiguration Capistrano 307 Konvention über Konfiguration 7 Layout 46, 146, 169 Action-spezifisch 149 dynamische Bestimmung 149 layout() 148 :except 149 Layoutzuweisung automatisch 147 Vererbung 148 explizit 148 Vererbung 148 Lazy Loading 72 Legacy-Datenbanken 271 Views 272 LightTPD konfigurieren 310 LightTPD starten 310 LightTPD und FastCGI 297 link to() 165, 274 link to remote() 240 :update 240 Listen 106 Load-Balancer 281 local request?() 293 lock version 120 Locking 119 Locomotive 15 Log-Dateien 299 Lokalisierung 179 mail to() 166 member() 227 Metadaten 75 Migration 382 Siehe Datenbankmigration 22 Migrationsskript 22 Mock-Objekte 378 mod fastcgi.so 295 Modellattribute testen 341 402 Modelllogik testen 342 Mongrel 296 Monitoring 300 multipart/form-data 284 MVC-Architektur 7 MySQL binary 273 N:M-Beziehungen 90 new 66 now() 137 number with delimiter() 162 observe() 119 observe field() 244 :frequency 244 :update 245 :url 245 :with 245 Tasks filtern 246 Observer 118 One-Click Ruby Installer 13 Optimistisches Locking 119 options for select() 164 options from collection for select() 165 paginate() 174 pagination links() 175 PaginationHelper 175 Paginator 174 params 127 Partials View 170 Fremder Controller 171 Lokale Variable 170 password field tag() 161 perform caching 275, 293 Performance 275 periodically call remote() 254 pluralize table names() 272 Polymorphe Assoziationen 94 POST-Request 274 prepend after filter() 141 prepend before filter() 141 Pretty URLs 142 Primärschlüssel 62 Product Backlog 19 Produktion, Anwendung 291 Stichwortverzeichnis Produktionsumgebung 293 Prototype 239 prototype.js 239 Quickstart Capistrano 304 radio button tag() 161 Rails-Umgebungen 291 RAILS ENV 291 Rake 339 clone structure to test 339 recent 339 test:functionals 339 test:units 339 rakefile 339 raw post() 247 read fragment() 278 Reaper 321 redirect to() 130 :controller 130 Redirects 129 Reload 130 Refactoring 347 Reflection 122 reload() 67 render() 124 :action 124 :layout 125, 149 :nothing 125 :status 125 :template 125 :text 125 xml 132 render component 172 render component as string() 173 Request Parameter 127 rescue action in public() 293 reset session() 134 respond to() 131 Responses 123 Rollback Capistrano 314 Rollen Capistrano 307 routes.rb 142 Routing 142 Stichwortverzeichnis Konfiguration 145 link to() 146 map.connect() 142 redirect to() 146 routes.rb 142 Ruby-Gettext-Package 184 save() 67 save with validation() 110 Scaffolding 345 SCGI 298 schema info 25 select() 164 select tag() 161 send data() 150, 286 :disposition 150 :filename 150 :type 150 data 150 send file() 150 :buffer size 151 :disposition 151 :stream 151 :type 150 filename 150 sichere Verwendung 269 Session 54 Daten löschen 134 Modellklassen 134 Session Optionen CGI::Session::ActiveRecordStore 136 session() 133 Session-Optionen 135 Sessions 133 Sessions aufräumen 299 set primary key() 63, 272 set table name() 64, 271 setup 354 setup() 330 show with errors() 288 Sicherheit 267 Single Table Inheritance 100 Skalierbarkeit 275 Skalierung 280 Datenbank-basierter Sessionspeicher 281 403 DEFAULT SESSION OPTIONS 281 horizontal 280 SOAP 226 SOAP-Client 235 sortable element() :update 251 :url 251 Spawner 320 SQL verwenden 73 SQL-Injection 267 vermeiden 268 start form tag() 33, 157 strip links() 162 stylesheet link tag() 167 Subversion 305 Tabellennamen 63 tag() 161 Tasks Capistrano 314 TDD 325 TDD-Kreislauf 333 teardown 354 teardown() 330 Template, HTML 153 Template, XML 177 Test Ausführen 340 Test-DSL 376 Test::Unit 328 Assertion 329 Test 329 Test Case 329 Test Suites 330 Test::Unit::TestCase 354 setup() 354 teardown() 354 use transactional fixtures 358 Testdatenbank 338 Erstellung 338 Konfiguration 338 Testgenerierung 337 Testgetriebene Softwareentwicklung 325, 333 Testumgebung 292 Testverzeichnisse 338 404 text area() 159 text field() 129, 158 text field tag() 160 text field with auto complete() 254 Timeout 295 Transaktionale Fixtures 358 Transaktionen 103 Capistrano 317 InnoDB 103 save () 104 truncate() 162 Umgebung definieren 291 Umgebungen in Rails 291 Unit Tests 325 assert generates() 367 assert no tag() 370 assert raise() 363 assert recognizes() 368 assert redirected to() 366 assert response() 365 assert routing() 368 assert tag() 369, 373 assert template() 370 Assertions – Übersicht 380 assigns() 368 Ausführen 331 Beispiel 326 Benennung von Testklassen 330 Controller-Tests 363 cookies() 368 CRUD-Test 358 Datencontainer-Assertions 368 Definition 325 delete() 365 Dynamische Sprachen 328 E-Mails testen 378 Fixtures 356 flash 371 flash() 368 get() 365 head() 365 Initialisierung von Template-Objekten 373 Instanzvariablen 372 Stichwortverzeichnis Integrationstests 374 Kontrollfluss-Assertions 365 Lange Ausführungszeiten 356 Mock-Objekte 378 Modellklassen 354 Was testen? 355 post() 365 put() 365 Rake 339 Routing-Assertions 367 session 371 session() 368 setup() 330 TDD-Kreislauf 333 teardown() 330 Template-Assertions 369 Test von Relationen 360 Testrezepte für Controller und Views 371 für Modelle 358 Tests für Fehlerbehandlung 363 TODO-Listen 334 Unabhängigkeit 332 Validierung 361 Views testen 373 Warum Testen? 327 Web Services testen 378 Werte im View 373 Up- und Downloads (Datei) 282 Controller 284 Download-View 286 Modell 283 Upload-View 284 update() 68 update all() 69 Upload von Dateien 160 URL, Direkteingabe mit ID 270 URL-Generierung 145 url for() 146 validate() 110 validate on create() 111 validate on update() 111 validates acceptance of() 112 validates associated() 112 validates confirmation of() 113 Stichwortverzeichnis validates each() 113 validates exclusion of() 113 validates format of() 113 validates inclusion of() 114 validates length of() 114 validates numericality of() 115 validates presence of() 47, 111 :message 111 :on 111 validates uniqueness of() 115 Validierung 47, 110 Validierungs-Klassenmethoden 111 Validierungsfehler, Anzeige 176 Variablen Capistrano 319 Vererbung 100 Base.inheritance column() 102 type 102 Versteckte Felder 160 View 153 Views testen 345 Web 2.0 237 Web Services 225 after invocation() 233 API-Klasse 226 api method() 226 Authentifzierung 233 before invocation() 233 Clients 234 Delegated Dispatching 231 Direct Dispatching 229 Einfache Datentypen 227 Endpoint URL 231 Filter 233 Generatoren 232 405 Grundlagen 225 Implementierung 228 Interfaces 226 Layered Dispatching 230 member() 227 Parameter-Formate 228 Scaffolding 229 SOAP 226 SOAP-Client 235 Strukturierte Datentypen 227 Testen 232 web service api() 229 web service dispatching mode() 229 web service scaffold() 229 WSDL 225 WSDL-Generierung 236 wsdl service name() 229 XML-RPC 226 web service api() 229 web service dispatching mode() 229 web service scaffold() 229 WEBrick 294 Start 21 Willkommensseite 16 WSDL 225 WSDL-Generierung 236 wsdl service name() 229 XML Builder 153 XML-RPC 226 XML-Template 177 XMLHttpRequest 238 YAML-Fixtures 356 Zusammengesetzte Schlüssel 272