You are on page 1of 33

RailsSpace.

Tworzenie
spoecznociowych
serwisw internetowych
w Ruby on Rails
Autor: Michael Hartl, Aurelius Prochazka
Tumaczenie: Marcin Rog
ISBN: 978-83-246-1633-6
Tytu oryginau: RailsSpace: Building a Social
Networking Website with Ruby on Rails
(Addison-Wesley Professional Ruby Series)
Format: 172x245, stron: 552

Poznaj Ruby on Rails i stwrz atrakcyjn witryn spoecznociow


Jak konfigurowa sesje bazodanowe?
Na czym polega trasowanie komentarzy?
W jaki sposb przygotowa stron przesyania awatarw?
Serwisy spoecznociowe, ktre gromadz ludzi o podobnych zainteresowaniach
i umoliwiaj komunikacj midzy znajomymi, ciesz si ogromn i wci rosnc
popularnoci. Dziki temu, e pozwalaj na wymian opinii i uatwiaj podtrzymywanie
globalnych kontaktw, staj si elementami strategii biznesowych i marketingowych wielu
firm. Do budowania takich serwisw doskonale nadaje si Rails, ktry oferuje klientom
witryny w peni dopasowane do potrzeb ich uytkownikw. Rails zosta napisany
w dynamicznym obiektowym jzyku Ruby z uyciem architektury MVC. Ten framework
wyrniaj przede wszystkim dwie reguy: regua DRY, polegajca na unikaniu
wykonywania tej samej pracy w rnych miejscach, oraz regua CoC., ktra pozwala
na zminimalizowanie niezbdnej konfiguracji przez zastpowanie jej gotowymi, domylnymi,
zalecanymi wzorcami. Rails umoliwia take uycie wtyczek, rozszerzajcych aplikacje
o rozmaite funkcjonalnoci np. logowanie, wrzucanie i skalowanie obrazkw czy tagowanie.
Ksika RailsSpace. Tworzenie spoecznociowych serwisw internetowych w Ruby
on Rails stanowi praktyczny kurs tworzenia interaktywnego serwisu spoecznociowego.
Za pomoc tego podrcznika nauczysz si budowa tak witryn, zaczynajc od statycznej
strony gwnej, przez utworzenie mechanizmu rejestracji i uwierzytelnienia uytkownikw,
a koczc na dynamicznej stronie WWW, z moliwoci przesyania obrazw i prowadzenia
blogw, oraz systemie dodawania znajomych.

Wydawnictwo Helion
ul. Kociuszki 1c
44-100 Gliwice
tel. 032 230 98 63
e-mail: helion@helion.pl

Konfigurowanie rodowiska programistycznego


Modelowanie i rejestrowanie uytkownikw
Testowanie
Ochrona stron
Zaawansowane logowanie
Aktualizacja informacji uytkownika
Tworzenie sieci spoecznej
Awatary
Model znajomoci
Blogi w technologii REST
Komentarze do blogu w technologii AJAX
Samodzielnie zbuduj funkcjonalny serwis spoecznociowy!!!

SPIS TRECI

S PIS TRECI

Spis rysunkw .................................................................................................... 13


Podzikowania .................................................................................................. 17
Rozdzia 1.

Wprowadzenie .................................................................................................. 19
1.1.
Dlaczego Rails? ...................................................................................... 19
1.1.1.
Produktywno chce by wolna .......................................... 20
1.1.2.
Ta produktywno nie jest wolna ....................................... 20
1.2.
Dlaczego ta ksika? ............................................................................. 21
1.3.
Kto powinien przeczyta t ksik? ................................................. 22
1.3.1.
Jak czyta t ksik? ............................................................. 22
1.3.2.
Jak oglda t ksik? .......................................................... 23
1.4.
Kilka historii zwizanych z Rails ........................................................ 23
1.4.1.
Aure .......................................................................................... 23
1.4.2.
Michael ..................................................................................... 25

Cz I

Podstawy ................................................................................. 29

Rozdzia 2.

Zaczynamy ......................................................................................................... 31
2.1.
Przygotowania ....................................................................................... 31
2.1.1.
Konfigurowanie rodowiska programistycznego ............ 33
2.1.2.
Praca z rails .............................................................................. 33
2.1.3.
Serwer deweloperski ............................................................. 35
2.2.
Nasze pierwsze strony ......................................................................... 37
2.2.1.
Generowanie kontrolera ....................................................... 38
2.2.2.
Kontroler Site .......................................................................... 41
2.2.3.
URL w Rails ............................................................................. 42
2.2.4.
Zmienianie trasy ..................................................................... 44
2.3.
Widoki w Rails ....................................................................................... 44
2.3.1.
Osadzony Ruby (ERb) ........................................................... 45

RAILSSPACE

2.4.

2.5.

Ukady ..................................................................................................... 47
2.4.1.
ERb, akcje i zmienne egzemplarza ...................................... 48
2.4.2.
Powtrka: podzia strony ...................................................... 50
2.4.3.
Dodawanie nawigacji ............................................................ 50
2.4.4.
Tablice asocjacyjne ................................................................. 51
2.4.5.
Symbole ................................................................................... 52
2.4.6.
Dopracowywanie link_to ..................................................... 53
2.4.7.
Kwestia stylu ........................................................................... 54
2.4.8.
Dopracowywanie nawigacji ................................................. 55
2.4.9.
Znajd co dla siebie .............................................................. 55
Programowanie ze stylem ................................................................... 56

Rozdzia 3.

Modelowanie uytkownikw ........................................................................ 61


3.1.
Tworzenie modelu User ....................................................................... 61
3.1.1.
Konfigurowanie bazy danych .............................................. 61
3.1.2.
Migracje i model User ........................................................... 64
3.1.3.
Pierwsza migracja uytkownika .......................................... 65
3.1.4.
Rake migracji .......................................................................... 66
3.2.
Walidacja modelu uytkownika ......................................................... 69
3.2.1.
Konsola .................................................................................... 70
3.2.2.
Prosta walidacja ...................................................................... 71
3.2.3.
Walidacje w akcji .................................................................... 75
3.2.4.
Poprawianie walidacji ........................................................... 75
3.2.5.
Porzdne walidacje ................................................................ 77
3.2.6.
Magiczne kolumny ................................................................ 80
3.3.
Dalsze kroki w celu zapewnienia integralnoci danych (?) ........... 82

Rozdzia 4.

Rejestrowanie uytkownikw ....................................................................... 85


4.1.
Kontroler User ....................................................................................... 85
4.2.
Rejestracja uytkownika widok ..................................................... 86
4.2.1.
Widok rejestracji wygld ................................................. 87
4.2.2.
Omwienie widoku rejestracji ............................................. 91
4.2.3.
Poprawianie formularza rejestracji ..................................... 93
4.2.4.
Zabawa z formularzami i funkcj debug ........................... 95
4.3.
Rejestracja uytkownika akcja ....................................................... 97
4.3.1.
Komunikaty o bdach formularza ................................... 103
4.3.2.
Flash ....................................................................................... 108
4.3.3.
Ukoczona funkcja register ................................................ 110
4.3.4.
Zarys gwnej strony uytkownika .................................. 111
4.4.
Doczanie rejestracji .......................................................................... 113
4.4.1.
Pliki pomocnicze .................................................................. 115
4.5.
Przykadowy uytkownik .................................................................. 118

Rozdzia 5.

Rozpoczynamy testowanie ........................................................................... 119


5.1.
Nasza filozofia testowania ................................................................. 120
5.2.
Konfiguracja testowej bazy danych ................................................. 120

SPIS TRECI

5.3.

5.4.

5.5.
5.6.

Rozdzia 6.

Testowanie kontrolera Site ................................................................ 121


5.3.1.
Niebanalny test ..................................................................... 122
5.3.2.
Nadmiar testw? .................................................................. 125
Testowanie rejestracji ......................................................................... 126
5.4.1.
Uruchamianie testw funkcjonalnych ............................. 126
5.4.2.
Podstawowe testy rejestracji .............................................. 126
5.4.3.
Testowanie rejestracji zakoczonej powodzeniem ........ 129
5.4.4.
Testowanie rejestracji
zakoczonej niepowodzeniem .......................................... 130
5.4.5.
Uruchamianie testw .......................................................... 133
5.4.6.
Wicej testw rejestracji? .................................................... 133
Podstawowe testy modelu User ....................................................... 133
5.5.1.
Podstawowe testy walidacji ............................................... 135
Szczegowe testy modelu User ....................................................... 137
5.6.1.
Testowanie niepowtarzalnoci .......................................... 138
5.6.2.
Testowanie dugoci pseudonimu .................................... 139
5.6.3.
Skorzystaj z konsoli ............................................................. 140
5.6.4.
Testowanie dugoci hasa .................................................. 142
5.6.5.
Testowanie wyrae regularnych ..................................... 144
5.6.6.
Uruchamianie wszystkich testw ...................................... 151

Logowanie i wylogowywanie ...................................................................... 153


6.1.
Utrzymywanie stanu za pomoc sesji ............................................. 154
6.1.1.
Konfigurowanie sesji bazodanowych ............................... 154
6.2.
Logowanie ............................................................................................ 156
6.2.1.
Rejestrowanie stanu zalogowania ..................................... 156
6.2.2.
Logowanie po zarejestrowaniu ......................................... 156
6.2.3.
Debugowanie ze zmienn sesji .......................................... 157
6.2.4.
Widok i akcja logowania ..................................................... 162
6.2.5.
Testowanie poprawnego logowania ................................. 165
6.2.6.
Testowanie nieprawidowego logowania ........................ 167
6.3.
Wylogowanie ....................................................................................... 168
6.3.1.
Testowanie wylogowania ................................................... 169
6.3.2.
Testowanie nawigacji .......................................................... 170
6.4.
Ochrona stron ...................................................................................... 173
6.4.1.
Chronienie stron w gupi sposb ...................................... 173
6.4.2.
Chronienie stron w mdry sposb .................................... 173
6.4.3.
Testowanie chronienia ........................................................ 176
6.5. Przyjazne przekazywanie URL .............................................................. 178
6.5.1.
Zmienna request .................................................................. 178
6.5.2.
Przyjazne przekierowywanie po zalogowaniu ............... 181
6.5.3.
Przyjazne przekierowywanie po rejestracji ..................... 183
6.5.4.
Przyjazne testowanie ........................................................... 184

RAILSSPACE

6.6.

Refaktoryzacja podstawowego logowania ..................................... 185


6.6.1.
Zalogowany? ......................................................................... 186
6.6.2.
Zaloguj! .................................................................................. 190
6.6.3.
Wyloguj! ................................................................................ 193
6.6.4.
Wyczy haso! ...................................................................... 194
6.6.5.
Obsuga formularza bez powtrze ................................. 197
6.6.6.
Przyjazne przekierowania bez powtrze ...................... 198
6.6.7.
Sprawdzamy poprawno .................................................. 200

Rozdzia 7.

Zaawansowane logowanie ............................................................................ 201


7.1.
A wic chcesz by zapamitany? ...................................................... 201
7.1.1.
Pole opcji zapamitaj mnie ............................................. 202
7.1.2.
Atrybut pamitaj mnie ..................................................... 205
7.1.3.
Cookie pamitaj mnie ...................................................... 206
7.2.
Faktyczne zapamitywanie uytkownika ....................................... 213
7.2.1.
Cookie uwierzytelniajce .................................................... 214
7.2.2.
Pamitanie, e zapamitalimy .......................................... 216
7.2.3.
Aktualizacja logout .............................................................. 218
7.2.4.
Bardziej bezpieczny plik cookie ........................................ 220
7.2.5.
Ukoczone (?) funkcje ......................................................... 222
7.3.
Testy zapamitywania uytkownikw ............................................ 224
7.3.1.
Poprawione testy logowania .............................................. 224
7.3.2.
Poprawiona funkcja wylogowania ................................... 230
7.4.
Testy zaawansowane testowanie integracji ............................... 230
7.4.1.
Testowanie pamitania cookie pierwsze cicie .......... 231
7.4.2.
Testowanie testu opowie ku przestrodze ................ 233
7.4.3.
Kilka refleksji dotyczcych testowania w Rails ............... 235
7.5.
Ponowna refaktoryzacja .................................................................... 235
7.5.1.
Refaktoryzacja remember ................................................... 236
7.5.2.
Refaktoryzacja forget ........................................................... 239
7.5.3.
Jeszcze dwie poprawki ........................................................ 240
7.5.4.
W peni zrefaktoryzowana funkcja login ......................... 241
7.5.5.
Kilka kocowych przemyle ............................................ 244

Rozdzia 8.

Aktualizacja informacji uytkownika ........................................................ 245


8.1.
Sensowniejsza strona centrum uytkownika ................................. 246
8.2.
Aktualizacja adresu e-mail ................................................................. 246
8.3.
Aktualizacja hasa ................................................................................ 248
8.3.1.
Obsuga przesyania hase .................................................. 253
8.4.
Testowanie edycji informacji o uytkownikach ............................ 257
8.4.1.
Funkcje pomocnicze dla testw ......................................... 259
8.4.2.
Testowanie strony edycji .................................................... 262
8.4.3.
Zaawansowany test ............................................................. 263

SPIS TRECI

8.5.

Czci ..................................................................................................... 266


8.5.1.
Dwie proste czci ................................................................ 266
8.5.2.
Bardziej zaawansowany plik czci .................................. 267
8.5.3.
Problem, a pniej koniec ................................................... 270
8.5.4.
Aktualizacja akcji login i register ....................................... 271

Cz II

Tworzenie sieci spoecznociowej ................................... 275

Rozdzia 9.

Profile osobiste ................................................................................................ 277


9.1.
Zacztek profilu uytkownika .......................................................... 277
9.1.1.
Adresy URL profilw ........................................................... 278
9.1.2.
Kontroler i akcje profilu ...................................................... 280
9.2.
Specyfikacja uytkownika ................................................................. 282
9.2.1.
Generowanie modelu Spec ................................................ 282
9.2.2.
Model Spec ............................................................................ 284
9.2.3.
czenie modeli .................................................................... 286
9.3.
Edycja specyfikacji uytkownika ...................................................... 288
9.3.1.
Kontroler Spec ...................................................................... 288
9.3.2.
Narzdzie dla HTML ........................................................... 290
9.3.3.
Widok edycji specyfikacji ................................................... 292
9.3.4.
Ochrona specyfikacji ........................................................... 293
9.3.5.
Testowanie specyfikacji ...................................................... 295
9.4.
Aktualizacja centrum uytkownika ................................................. 299
9.4.1.
Nowy widok centrum uytkownika ................................. 300
9.4.2.
Pole specyfikacji ................................................................... 303
9.4.3.
Trasy nazwane i adres URL profilu .................................. 305
9.4.4.
Gwna zawarto centrum uytkownika ....................... 307
9.5.
Osobisty FAQ zainteresowania i osobowo ............................. 310
9.5.1.
Model FAQ ............................................................................ 311
9.5.2.
Kontroler FAQ ...................................................................... 314
9.5.3.
Edycja FAQ ........................................................................... 315
9.5.4.
Dodawanie FAQ do centrum uytkownika .................... 317
9.5.5.
Testy FAQ .............................................................................. 320
9.6.
Upublicznianie profilu ....................................................................... 322

Rozdzia 10.

Spoeczno ..................................................................................................... 325


10.1. Tworzenie spoecznoci (kontroler) ................................................. 325
10.2. Wprowadzanie przykadowych uytkownikw ........................... 326
10.2.1. Zbieranie danych ................................................................. 327
10.2.2. adowanie danych .............................................................. 328
10.3. Spis czonkw spoecznoci ............................................................... 330
10.3.1. Nowy trik funkcji find ......................................................... 331
10.3.2. Akcja index ............................................................................ 334
10.3.3. Spis alfabetyczny .................................................................. 336
10.3.4. Wywietlanie wynikw indeksu ....................................... 338

10

RAILSSPACE

10.4.

Dopracowywanie wynikw .............................................................. 343


10.4.1. Dodawanie paginacji ........................................................... 343
10.4.2. Podsumowanie wynikw ................................................... 347

Rozdzia 11.

Wyszukiwanie i przegldanie ...................................................................... 349


11.1. Wyszukiwanie ..................................................................................... 349
11.1.1. Widoki wyszukiwania ......................................................... 350
11.1.2. Ferret ...................................................................................... 353
11.1.3. Wyszukiwanie za pomoc funkcji
find_by_contents .................................................................. 355
11.1.4. Dodawanie paginacji do wyszukiwania .......................... 357
11.1.5. Wyjtek od reguy ................................................................ 361
11.2. Testowanie wyszukiwania ................................................................ 363
11.3. Rozpoczynamy przegldanie ............................................................ 366
11.3.1. Strona przegldania ............................................................. 366
11.3.2. Wyszukiwanie wedug wieku, pci i miejsca pobytu
(na razie bez tego ostatniego) ............................................. 368
11.4. Miejsce pobytu ..................................................................................... 372
11.4.1. Lokalna baza danych informacji geograficznych ........... 373
11.4.2. Uywanie GeoData do wyszukiwania
wedug miejsca pobytu ....................................................... 375
11.4.3. Nazwy lokalizacji ................................................................. 378
11.4.4. Dodawanie walidacji przegldarki ................................... 381
11.4.5. Ukoczona strona gwna spoecznoci .......................... 386

Rozdzia 12.

Awatary ............................................................................................................ 389


12.1. Przygotowania do przesania awataru ............................................ 389
12.1.1. Dostosowywanie modelu ...................................................... 390
12.1.2. Strona przesyania awatarw ................................................ 392
12.1.3. Plik czci awataru .................................................................. 396
12.2. Operowanie na awatarach ................................................................ 397
12.2.1. ImageMagick i convert ........................................................... 398
12.2.2. Metoda save ............................................................................. 401
12.2.3. Dodawanie walidacji .............................................................. 402
12.2.4. Usuwanie awatarw ............................................................... 406
12.2.5. Testowanie awatarw ............................................................. 409

Rozdzia 13.

E-mail ................................................................................................................ 413


13.1. Action Mailer ........................................................................................ 413
13.1.1. Konfiguracja .......................................................................... 414
13.1.2. Przypominanie hasa ........................................................... 415
13.1.3. Tworzenie odnonika i dostarczanie
przypomnienia ..................................................................... 416
13.1.4. Testowanie przypominania ................................................ 420
13.2. Podwjnie lepy system e-mail ......................................................... 423
13.2.1. Odnonik e-mail ................................................................... 424

SPIS TRECI

13.2.2.
13.2.3.
13.2.4.

11

Akcja correspond i formularz e-mail ................................. 425


Wiadomo e-mail ................................................................ 427
Testowanie podwjnie lepego systemu
poczty elektronicznej .......................................................... 430

Rozdzia 14.

Znajomoci ....................................................................................................... 435


14.1. Tworzenie modelu znajomoci ......................................................... 435
14.1.1. Znajomoci w abstrakcji ...................................................... 436
14.1.2. Model znajomoci ................................................................ 437
14.1.3. Tworzenie oczekujcych znajomoci ................................ 439
14.1.4. Propozycja zawarcia znajomoci ....................................... 440
14.1.5. Koczenie modelu Friendship ........................................... 441
14.1.6. Testowanie modelu Friendship ......................................... 443
14.2. Propozycje znajomoci ....................................................................... 444
14.2.1. Odnonik do propozycji znajomoci ................................ 444
14.2.2. Sterowanie propozycj ........................................................ 446
14.3. Zarzdzanie znajomociami .............................................................. 449
14.3.1. has_many :through .............................................................. 449
14.3.2. Centrum znajomoci ............................................................ 452
14.3.3. Akcje dla znajomoci ........................................................... 455
14.3.4. Testowanie propozycji znajomoci ................................... 458

Rozdzia 15.

Blogi w technologii REST ............................................................................. 461


15.1. Zasugujemy na REST ........................................................................ 462
15.1.1. REST i CRUD ........................................................................ 463
15.1.2. Modyfikatory URL ............................................................... 465
15.1.3. So;w pokoju ....................................................................... 466
15.1.4. Odpowiadanie na formaty i darmowe API ..................... 468
15.2. Rusztowania dla blogw zgodnych z REST ................................... 469
15.2.1. Pierwszy zasb REST ........................................................... 469
15.2.2. Wpisy do blogu .................................................................... 471
15.2.3. Kontroler Post ....................................................................... 474
15.3. Tworzenie prawdziwego blogu ........................................................ 478
15.3.1. czenie modeli .................................................................... 478
15.3.2. Trasowanie blogu i wpisu ................................................... 479
15.3.3. Kontroler Posts ..................................................................... 480
15.3.4. Zarzdzanie blogiem ........................................................... 483
15.3.5. Tworzenie wpisw ............................................................... 485
15.3.6. Wywietlanie wpisw ......................................................... 487
15.3.7. Edycja wpisw ...................................................................... 490
15.3.8. Publikowanie wpisw ......................................................... 493
15.3.9. Ostatni, denerwujcy szczeg .......................................... 495
15.4. Testy REST ............................................................................................ 498
15.4.1. Domylne testy funkcjonalne REST .................................. 498
15.4.2. Dwa niestandardowe testy ................................................. 501

12

RAILSSPACE

Rozdzia 16.

Komentarze do blogu w technologii Ajax ................................................. 503


16.1. Komentarze zgodne z REST .............................................................. 503
16.1.1. Zasb Comments ................................................................. 504
16.1.2. Model i powizania komentarza ....................................... 505
16.1.3. Kontroler Comments
i zapobiegawczy widok czci ........................................... 507
16.1.4. Trasowanie komentarzy ..................................................... 508
16.2. Wprowadzamy Ajaksa ....................................................................... 509
16.2.1. Nowe komentarze ................................................................ 510
16.2.2. Tworzenie komentarzy ....................................................... 514
16.2.3. Niszczenie komentarzy ....................................................... 517
16.3. Efekty wizualne ................................................................................... 519
16.3.1. Pliki RJS i pierwszy efekt .................................................... 520
13.3.2. Kolejne dwa efekty .............................................................. 521
16.3.3. Przycisk anuluj ..................................................................... 523
16.3.4. Zgrabna degradacja ............................................................. 524
16.4. Debugowanie i testowanie ................................................................ 526
16.4.1. Inne spojrzenie na new ....................................................... 526
16.4.2. Testowanie Ajax za pomoc xhr ........................................ 527

Rozdzia 17.

Co dalej? ........................................................................................................... 529


17.1. Co naley wzi pod uwag? ............................................................ 529
17.1.1. Wybr sprztu i oprogramowania .................................... 530
17.1.2. Praca w trybie produkcyjnym ............................................ 530
17.1.3. Minimalny serwer produkcyjny ........................................ 532
17.1.4. Skalowanie ............................................................................ 534
17.1.5. Podstawy administrowania ................................................ 536
17.2. Wicej Ruby on Rails .......................................................................... 539
Skorowidz ......................................................................................................... 541

R OZDZIA 10.

Spoeczno
Umoliwienie uytkownikom tworzenia i edycji profilw jest dobrym pocztkiem, ale
jeeli RailsSpace ma by przydatne swoim czonkom, musimy im da moliwo odnalezienia siebie nawzajem. W tym i kolejnym rozdziale utworzymy trzy metody wyszukania uytkownikw:
1. Prosty spis imion i nazwisk.
2. Przegldanie wedug wieku, pci i miejsca pobytu.
3. Penotekstowe wyszukiwanie we wszystkich informacjach o uytkowniku, cznie
ze specyfikacj i FAQ.
W tym rozdziale umiecimy w deweloperskiej bazie danych RailsSpace przykadowych uytkownikw, aby nasze prby odnalezienia uytkownika nie byy bezcelowe.
Nastpnie utworzymy alfabetyczny spis spoecznoci, aby utworzy najprostsz list
czonkw RailsSpace. Cho prosty, spis czonkw RailsSpace pozwoli nam pozna
kilka nowych aspektw Rails, takich jak paginacja wynikw oraz niesamowita elastyczno funkcji find.

10.1. TWORZENIE SPOECZNOCI


(KONTROLER)
Do wyszukania uytkownika bdzie mona uy spisu czonkw spoecznoci, a take
przegldarki i wyszukiwarki uytkownikw. Przeglda i wyszukiwa s czasownikami, co sugeruje, e powinny by akcjami wewntrz kontrolera. Chcemy kontynuowa konwencj uywania rzeczownikw dla nazw kontrolerw, wic potrzebujemy
odpowiedniego rzeczownika zbiorowego do opisania zbioru uytkownikw, ktry
moe by przegldany i przeszukiwany. Poniewa wyszukiwanie bdzie odbywao si
w spoecznoci uytkownikw, utworzymy kontroler Community (spoeczno):

326

RAILSSPACE

> ruby script/generate controller Community index browse search


exists app/controllers/
exists app/helpers/
create app/views/community
exists test/functional/
create app/controllers/community_controller.rb
create test/functional/community_controller_test.rb
create app/helpers/community_helper.rb
create app/views/community/index.rhtml
create app/views/community/browse.rhtml
create app/views/community/search.rhtml

Dziki temu uytkownicy bd mogli (na przykad) wyszukiwa innych uytkownikw z uyciem URL
http://localhost:3000/community/search
i podobnie dla przegldania (akcja browse). Zaktualizujmy teraz pasek nawigacji:

LISTING 10.1. app/views/layouts/application.rhtml


.
.
.
<%= nav_link "Pomoc",
<%= nav_link "Spoeczno",
.
.
.

"site", "help" %> |


"community", "index" %>

Dalsz cz tego rozdziau oraz rozdzia nastpny powicimy wypenianiu kontrolera Community. Jednak najpierw musimy rozwiza problem podstawowy. W obecnej
postaci wszystkie wysiki podejmowane, by odnale uytkownikw RailsSpace,
spezn na niczym.

10.2. WPROWADZANIE PRZYKADOWYCH


UYTKOWNIKW
Poniewa niszowa witryna spoecznociowa, jak jest RailsSpace, moe mie setki,
a nawet tysice uytkownikw, powinnimy j rozwija, stosujc baz danych zawierajc wiele przykadowych wpisw. Dziki temu rne sposoby przegldania i wyszukiwania bd zwracay realistyczn liczb wynikw. Jednake w tej chwili dysponujemy tylko jednym uytkownikiem naszym starym przyjacielem Foo Barem
a dodawanie uytkownikw samodzielnie, tak jak to robilimy z Foo, byoby niezwykle praco- i czasochonne. Co wicej, nasza deweloperska baza danych jest podatna na
zniszczenie przez migracje i inne katastrofy. Nawet gdybymy wprowadzili samodzielnie dane wielu uytkownikw, ryzykowalibymy utracenie tych danych.

Rozdzia 10. SPOECZNO

327

Naszym rozwizaniem jest wykorzystanie komputera do cikiej pracy. Utworzymy


pliki YAML zawierajce przykadow baz danych uytkownikw (a take odpowiadajce im specyfikacje i FAQ). Nastpnie zautomatyzujemy adowanie tych danych za
pomoc wasnego zadania Rake.

10.2.1. ZBIERANIE DANYCH


W tym podrozdziale utworzymy przykadowe dane uytkownikw, specyfikacje i FAQ
w formacie YAML. Naszym rdem bd informacje o wyrnionych absolwentach
(Distinguished Alumni) Caltechu, dostpne publicznie pod adresem:
http://alumni/clatech.edu/distinguished_alumni.
Jeeli wolisz wypeni pliki z danymi w inny sposb nawet piszc je samodzielnie
moesz to zrobi. Chodzi o to, aby mie dane w formacie, ktry moe by atwo zaadowany na danie, dziki czemu w sytuacji, gdy co si stanie bazie danych, bdziemy
mogli atwo przywrci jej poprzedni stan.
Gdyby by zwykym miertelnikiem, musiaby samodzielnie przepisywa informacje
ze strony Distinguished Alumni, ale poniewa to Aure tworzy witryn Caltech Alumni,
przykadowe dane s dostpne do pobrania w formacie YAML:
http://alumni.caltech.edu/distinguished_alumni/users.yml
http://alumni.caltech.edu/distinguished_alumni/specs.yml
http://alumni.caltech.edu/distinguished_alumni/faqs.yml.
Te same pliki z danymi s dostpne pod adresem:
ftp://ftp.helion.pl/przyklady/railsp.
Aby uzyska wyniki przedstawiane w tym rozdziale, powiniene pobra te pliki YAML
i umieci je w katalogu
lib/tasks/sample_data
(bdzie to wymagao utworzenia katalogu sample_data).
Przy okazji, dane o wyrnionych absolwentach s mieszank informacji prawdziwych
i faszywych. Uylimy prawdziwych imion i nazwisk oraz oficjalnych biografii (ktre
wykorzystalimy w polu FAQ dla yciorysu), ale zmylilimy daty urodzenia, miejsca
pobytu i wiek. W przypadku miejsc pobytu umiecilimy kody pocztowe w zakresie
od 92101 (San Diego) do 98687 (Vancouver). W przypadku dat urodzenia tworzymy
wraenie, e absolwenci dostali nagrod Distinguished Alumni w wieku 50 lat i przypisujemy im dat urodzenia 1 stycznia 50 lat przed otrzymaniem nagrody.

328

RAILSSPACE

10.2.2. ADOWANIE DANYCH


Majc przykadowe dane uytkownikw, musimy je skopiowa z plikw YAML do
bazy danych. W zasadzie nadaje si do tego kada technika moemy parsowa plik,
korzystajc z Ruby (a nawet powiedzmy Perla, czy Pythona), ustanowi jakiego
rodzaju poczenie bazy danych albo te jawnie wykona wszystkie wstawienia. Jeeli
jednak si zastanowisz, Rails musi mie ju jaki sposb, by to zrobi, poniewa testy
w Rails umieszczaj w testowej bazie danych informacje z plikw YAML, korzystajc
z plikw fixture. Nasz sposb bdzie polega na zastosowaniu tego mechanizmu do
wstawienia przykadowych danych do deweloperskiej bazy danych.
Moglibymy napisa skrypt w czystym Ruby, aby wykona wstawienie danych, ale
rozwizaniem bardziej zgodnym z duchem Rails jest utworzenie w tym celu wasnego
zadania Rake. Wie si to z napisaniem wasnego Rakefile. Nie powinno zaskoczy Ci, e na takie pliki Rakefile znajduje si specjalne miejsce w drzewie katalogw Rails katalog lib/tasks (teraz ju wiesz, czemu umiecilimy dane w katalogu lib/tasks/sample_data).
Poniewa nasze zadania Rake wi si z adowaniem przykadowych danych, nazwiemy nasz plik sample_data.rake. Pliki Rakefile zawieraj serie zada napisanych w Ruby.
W naszym przypadku zdefiniujemy zadania load i delete:

LISTING 10.2. lib/tasks/sample_data.rake


# Zawiera zadania umoliwiajce wczytanie i usunicie przykadowych danych uytkownikw
require 'active_record'
require 'active_record/fixtures'
namespace :db do
DATA_DIRECTORY = "#{RAILS_ROOT}/lib/tasks/sample_data"
namespace :sample_data do
TABLES = %w(users specs faqs)
MIN_USER_ID = 1000 # Pocztkowy identyfikator uytkownika w danych przykadowych
desc "adowanie przykadowych danych."
task :load => :environment do |t|
class_name = nil # Uywamy nil, aby Rails sam wybra klas
TABLES.each do |table_name|
fixture = Fixtures.new(ActiveRecord::Base.connection,
table_name, class_name,
File.join(DATA_DIRECTORY,
table_name.to_s))
fixture.insert_fixtures
puts "Zaadowano dane z #{table_name}.yml"
end
end
desc "Usuwa przykadowe dane"
task :delete => :environment do |t|

Rozdzia 10. SPOECZNO

329

User.delete_all("id
>= #{MIN_USER_ID}")
Spec.delete_all("user_id >= #{MIN_USER_ID}")
Faq.delete_all( "user_id >= #{MIN_USER_ID}")
end
end
end

Nasza metoda wczytywania danych wykorzystuje pliki fixture, wic u gry pliku Rakefile
umiecilimy deklaracj require dla biblioteki fixtures Active Record. Zgodnie ze
standardow praktyk w plikach Rakefile poprzedzamy kade zadanie opisem (desc).
Dziki temu, gdy zapytamy rake o dostpne zadania, opisy load i delete zostan
wywietlone na licie:
> rake --tasks
.
.
.
rake db:sample_data:delete # Usuwa przykadowe dane
rake db:sample_data:load
# adowanie przykadowych danych
.
.
.

Zwr uwag, e poprzez umieszczenie definicji zada w blokach namespace sprawiamy, e zadania Rake mog by wywoywane za pomoc tej samej skadni, ktr
widzielimy przy okazji innych zada, takiej jak:
> rake db:test:prepare

Zadanie load tworzy fixture za pomoc metody Fixture.new, ktra przyjmuje poczenie do bazy danych, nazw tabeli, nazw klasy i pen ciek do danych fixture:
Fixtures.new(connection, table_name, class_name, fixture_path)

Poniewa ustawilimy class_name na nil, Rails bdzie prbowa wywnioskowa


nazw klasy z nazwy tablicy. Skonstruowalimy te rne cieki, korzystajc z File.
join, ktra tworzy ciek do pliku odpowiedni dla danej platformy. Po utworzeniu fixture wstawiamy dane do bazy, korzystajc z metody insert_fixtures.
Moemy cofn dziaanie load, stosujc zadanie delete, wykorzystujce funkcj
Active Record delete_all do usunicia wszystkich danych odpowiadajcych uytkownikom, ktrych identyfikator ma warto wiksz ni 1000 (tym samym pozostawia uytkownikw takich jak Foo Bar, ktrych identyfikator ma mniejsz warto).
A skd fixture wie o (na przykad) klasie User? I skd wie, w jaki sposb poczy si
z baz danych? Odpowied tkwi w magicznym wierszu:
task :load => :environment do |t|

(i podobnie dla zadania delete). Wiersz ten oznacza, e zadanie load zaley od rodowiska Rails. Rake odpowiada poprzez wczytanie lokalnego (deweloperskiego)

330

RAILSSPACE

rodowiska Rails, cznie z modelami i poczeniami do bazy danych (ktre pobiera


z pliku database.yml). Korzystajc Rails do obsugi wszystkich tych szczegw, Rake
redukuje system do wczeniej rozwizanego problemu.
Jeeli chcesz, aby Twoje wyniki byy zgodne z naszymi, zanim przejdziesz dalej, uruchom zadanie Rake, aby wczyta przykadowe dane:
> rake db:sample_data:load
(in /rails/rails_space)
Zaadowano dane z users.yml
Zaadowano dane z specs.yml
Zaadowano dane z faqs.yml

10.3. SPIS CZONKW SPOECZNOCI


Tak jak w przypadku wszystkich pozostaych kontrolerw, utworzylimy akcj index
dla kontrolera Community ale po raz pierwszy nazwa index ma tu sens, poniewa moemy wykorzysta t stron jako alfabetyczny indeks (spis) czonkw spoecznoci RailsSpace. Projekt, ktry chodzi nam po gowie, jest prosty. Wystarczy poczy
kad z liter alfabetu z uytkownikami RailsSpace, ktrych nazwisko rozpoczyna si
od tej litery.
Implementacja tego projektu wymaga kilku rnych warstw, wcznie z paroma plikami czci i opanowaniem nowych waciwoci Active Record. Podczas implementowania rnych fragmentw warto wiedzie, dokd zmierzamy (rysunek 10.1). Zwr
uwag, e adres URL
http://localhost:3000/community/index/H
zawiera cay zestaw parametrw kontroler, akcj i identyfikator obsugiwanych
przez domyln tras w pliku routes.rb (punkt 2.2.4):

LISTING 10.3. config/routes.rb


ActionController::Routing::Routes.draw do |map|
.
.
.
# Install the default route as the lowest priority
map.connect ' :controller/:action/:id'
end

Warto wspomnie, e kady z tych trzech elementw jest dostpny w zmiennej params.
Na przykad w tym przypadku params[:id] wynosi H.

Rozdzia 10. SPOECZNO

331

RYSUNEK 10.1. Ukoczony spis spoecznoci (pokazany dla litery H)

10.3.1. NOWY TRIK FUNKCJI FIND


Akcja index kontrolera Community bdzie musiaa wyszuka wszystkich uytkownikw, ktrych inicja nazwiska to podana litera. Jak pamitamy z podrozdziau 9.2,
informacje o imieniu i nazwisku znajduj si w specyfikacji uytkownika. Musimy
w jaki sposb przeszuka specyfikacje, aby odnale odpowiednie nazwiska.

332

RAILSSPACE

Moglibymy dokona tego typu wyszukiwania za pomoc surowego kodu SQL, stosujc symbol zastpczy % do wyszukania wszystkich nazwisk rozpoczynajcych si
(na przykad) liter N i wywietleniu wynikw w kolejnoci alfabetycznej wedug
nazwiska1:
SELECT * FROM specs WHERE last_name LIKE 'N%'
ORDER BY last_name, first_name

Co oczywiste, Active Record zapewnia warstw abstrakcji dla tego typu zapytania.
Bardziej zaskakujcy jest fakt, e rozwizanie wykorzystuje metod find, ktr wczeniej widzielimy przy wyszukiwaniu elementw wedug identyfikatora:
User.find(session[:user_id])

To nie jest kres moliwoci metody find. Jest to funkcja cakiem elastyczna, ktra
potrafi wykona wiele rnych zapyta. Konkretnie, przesyajc do funkcji find opcje
:all, :conditions i :order, moemy wyszuka wszystkich uytkownikw, ktrych
nazwiska rozpoczynaj si od litery N:
> ruby script/console
Loading development environment.
>> initial = "N"
>> Spec.find(:all, :conditions => "last_name LIKE '#{initial}%'",
?> :order => "last_name, first_name")
=> [#<Spec:0x36390a4 @attributes={"city"=>"", "occupation"=>"",
"birthdate"=>"19
36-01-01", "zip_code"=>"96012", "gender"=>"Male", "id"=>"731",
"first_name"=>"Ro
ddam", "user_id"=>"1117", "last_name"=>"Narasimha", "state"=>""}>,
#<Spec:0x3638
f3c @attributes={"city"=>"", "occupation"=>"",
"birthdate"=>"1945-01-01", "zip_c
ode"=>"96045", "gender"=>"Male", "id"=>"655", "first_name"=>"Jerry",
"user_id"=>
"1118", "last_name"=>"Nelson", "state"=>""}>, #<Spec:0x3638dac
@attributes={"cit
y"=>"", "occupation"=>"", "birthdate"=>"1941-01-01",
"zip_code"=>"96079", "gende
r"=>"Male", "id"=>"713", "first_name"=>"Navin", "user_id"=>"1119",
"last_name"=>
"Nigam", "state"=>""}>, #<Spec:0x3638ba4 @attributes={"city"=>"",
"occupation"=>
"", "birthdate"=>"1939-01-01", "zip_code"=>"96112", "gender"=>"Male",
"id"=>"723
", "first_name"=>"Robert", "user_id"=>"1120", "last_name"=>"Noland",
"state"=>""
}
1

Posortowanie wynikw wedug last_name, first_name porzdkuje je najpierw wedug nazwiska,


a potem imienia, dziki czemu na przykad Michelle Feynman znajdzie si przed Richardem Feynmanem, a oboje zostan wywietleni przed Murrayem Gellem-Manem.

Rozdzia 10. SPOECZNO

333

Powyszy kod daje taki sam wynik jak czysty SQL przedstawiony wczeniej i w obecnej
postaci dziaa dobrze. Oczekujemy jednak, e w RailsSpace inicja bdzie pochodzi
z internetu i bdzie dostarczany za porednictwem params[:id]. Poniewa uytkownik moe wpisa dowolny inicja, zoliwy haker mgby umieci w params[:id]
acuch zdolny do wykonania dowolnych instrukcji SQL cznie (ale nie tylko)
z usuniciem bazy danych2. Aby zapobiec takiemu atakowi zwanemu wstrzykniciem
kodu SQL musimy zabezpieczy wszystkie acuchy wstawiane do instrukcji SQL.
W Active Record mona to zrobi, uywajc znaku ? jako symbolu zastpczego:
Spec.find(:all, :contditions => ["last_name LIKE ?", initial+"%"],
:order => "last_name, first_name")

Dziki temu, gdy uytkownik wpisze


http://RailsSpace.com/community/index/<niebezpieczny acuch>

aby uruchomi niebezpieczne zapytanie, niebezpieczny acuch zostanie przeksztacony na co niegronego przed wstawieniem do klauzuli warunkw. Tak si skada, e
nie moemy napisa
:condiotions => ["last_name LIKE ?%", initial]

poniewa Rails prbowaby uruchomi zapytanie zawierajce


last_name LIKE 'N'%

co jest nieprawidowe.
Zwr uwag, e w przypadku bezpiecznej wersji wartoci :conditions nie jest
acuch, a tablica, ktrej pierwszy element jest acuchem zawierajcym warunki,
a kolejnymi elementami s acuchy, ktre powinny by zabezpieczane i wstawiane.
Moemy wymusi kilka warunkw, stosujc kilka znakw zapytania3:
Spec.find(:all, :conditions => ["first_nam = ? AND last_name = ?",
"Foo", "Bar"])

Oczywicie w powyszym przypadku moglibymy rwnie zapisa


Spec.find_by_first_name_and_last_name("Foo", "Bar")

A funkcja ta sama zastosuje zabezpieczenia. Jest to przykad tego, jak przy uruchamianiu zapyta SQL Active Record umoliwia przechodzenie na rne poziomy
abstrakcji, dajc uytkownikowi to, co najlepsze z dwch wiatw domylnie
wygod, a w ramach potrzeb maksimum moliwoci (patrz ramka Przebijanie si
przez abstrakcj).

Nawet jeeli Rails bdzie mia dostp do bazy danych jako uytkownik MySQL z ograniczonymi
prawami dostpu (a tak na pewno bdzie w rodowisku produkcyjnym), umoliwienie wydawania
dowolnych polece wci jest Ze.
Drugi sposb wstawiania wielu warunkw znajdziesz w punkcie 11.3.2.

334

RAILSSPACE

Przebijanie si przez abstrakcj


Jedn z gwnych zasad projektowych Rails jest zapewnienie warstwy atwych w uyciu
funkcji wysokiego poziomu dla powszechnie wykonywanych zada, ale rwnie pozostawienie furtki do korzystania z warstw lecych poniej. Na przykad widzielimy,
e w celu odnalezienia uytkownika wedug pseudonimu i hasa Rails tworzy funkcj
o nazwie
User.find_by_screen_name_and_password(screen_name, password)

Widzielimy rwnie, jak zej do niszej warstwy, korzystajc z funkcji find:


spec = Spec.find(:all, :conditions => "last_name LIKE 'N%'",
:order => "last_name, first_name"

Jeeli chcesz, moesz zej do kolejnej warstwy i uy czystego kodu SQL:


spec = Spec.find_by_sql("SELECT * FROM specs
WHERE last_name LIKE 'N%'
ORDER BY last_name, first_name")

Jest to takie samo zapytanie jak powysze, ale poniewa find_by_sql stosuje czysty
SQL, moemy w ten sposb dokonywa dowolnych zapyta4. A wic na przykad, jeeli
wskim gardem aplikacji jest jakie nadmiernie rozbudowane zapytanie co czasem
mona doskonale rozwiza za pomoc czystego kodu SQL zawsze moesz przej
do najniszej warstwy i utworzy optymalne rozwizanie.

10.3.2. AKCJA INDEX


Jak wspominalimy wczeniej, spis czonkw spoecznoci bdzie stanowi katalog
uytkownikw witryny RailsSpace. Dziki nowym umiejtnociom, ktre nabylimy
w pracy z Active Record, moemy pobra dane uytkownikw, ktrych nazwisko rozpoczyna si okrelon liter. Oprcz tego musimy tylko utworzy kilka zmiennych
egzemplarza do wykorzystania w widokach:

LISTING 10.4. app/controllers/community_controller.rb


class CommunityController < ApplicationController
helper :profile
def index
@title = "Spoeczno"
@letters = "ABCDEFGHIJKLMNOPRSTUWXYZ".split("")
if params[:id]
@initial = params[:id]
specs = Spec.find(:all,

Dla naprawd dowolnych zapyta moesz nawet uy Active::Record::Base.connection.execute


(query), gdzie query jest czystym poleceniem SQL, takim jak "DROP TABLE users".

Rozdzia 10. SPOECZNO

335

:conditions => ["last_name like ?",


@initial+'%'],
:order => "last_name, first_name")
@users = specs.collect { |spec| spec.user }
end
end
def browse
end
def search
end
end

Zwr uwag, e doczylimy plik pomocniczy Profile (stosujc helper :profile),


poniewa w spisie czonkw spoecznoci uyjemy profile_for do utworzenia
odnonikw do profili uytkownikw.
W tej akcji znajduje si kilka nowych elementw skadni Ruby. Pierwszym i najprostszym jest
"ABCDEFGHIJKLMNOPRSTUWXYZ".split("")

Tworzona jest tablica acuchw, po jednym dla kadej litery alfabetu. Wykorzystujemy tutaj metod split, ktr moesz zna z Perla, Pythona lub jednego z wielu
jzykw, w ktrych istnieje podobna funkcja. Najczciej funkcja split jest uywana
do dzielenia acucha na tablic na podstawie biaego znaku, ale moe rwnie dzieli
na podstawie innych acuchw, co pokazuje ten przykad w irb:
> irb
irb(main):001:0> "foo bar baz".split
=> ["foo", "bar", "baz"]
irb(main):002:0> "1foo2fooredfoobluefoo".split("foo")
=> ["1", "2", "red", "blue"]

W przypadku akcji index uycie pustego acucha "" rozdziela podany acuch na jego
znaki skadowe:
irb(main):003:0> "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("")
=> ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
"N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]

(Oczywicie moglibymy rwnie napisa


%w(A B C D E F G H I J K M N O P R S T U W X Y Z )

jednak byoby to wicej wpisywania, ni bymy chcieli, a poza tym ju najwyszy czas,
abymy przedstawili istotn funkcj split).
Drugim i bardziej istotnym fragmentem skadni Ruby jest nasza metoda tworzenia
zmiennej egzemplarza @users. W akcji index spoecznoci wiersz
users = specs.collect { |spec| spec.user }

336

RAILSSPACE

kroczy przez specs i tworzy tablic odpowiednich uytkownikw5. Jak moesz domyle si z kontekstu, nawiasy klamrowe {} s alternatywn skadni blokw Ruby.
Dziaanie przedstawionego tu kodu jest w zasadzie identyczne6 jak skadni, ktrej uywalimy poprzednio, czyli doend:
users = specs.collect do |spec|
spec.user
end

Jeeli chcesz, moesz uy skadni z nawiasami w kilku wierszach:


users = specs.collect { |spec|
spec.user
}

Wybr wersji jest po prostu kwesti konwencji. My przestrzegamy konwencji prezentowanej w dwch naszych ulubionych ksikach o Ruby Programowanie w jzyku Ruby
oraz Ruby. Tao programowania w 400 przykadach: uywaj skadni z nawiasami w blokach
jednowierszowych, a skadni doend w blokach wielowierszowych.

10.3.3. SPIS ALFABETYCZNY


Czas zaprzc nasze zmienne egzemplarza do pracy w widoku spisu spoecznoci.
Rozpoczniemy od samego wywietlenia spisu, ktry bdzie po prostu list liter:

LISTING 10.5. app/views/community/index.rhtml


<h2><%= @title %></h2>
<fieldset>
<legend>Spis alfabetyczny</legend>
<% @letters.each do |letter| %>
<% letter_class = (letter == @initial) ? "letter_current" :
"letter" %>
<%= link_to letter, {:action => "index", :id => letter },
:class => letter_class %>
<% end %>
<br clear="all" />
</fieldset>

Iterujemy przez wszystkie litery alfabetu, korzystajc z metody each (inny sposb
znajdziesz w ramce for letter in @letters? ) i dla kadej litery definiujemy klas
CSS (za pomoc operatora trjkowego), aby okreli, czy dana litera jest aktualnie
wybrana. Nastpnie tworzymy odnonik powrotny do strony index z biec liter
jako identyfikatorem (parametrem id).

Metod collect widzielimy po raz pierwszy w punkcie 5.6.5 podczas tworzenia listy poprawnych
adresw e-mail dla testowania walidacji.
Jedyn rnic jest fakt, e nawiasy maj pierwszestwo przed doend, ale to rzadko ma znaczenie.

Rozdzia 10. SPOECZNO

337

for letter in @letters?


Do skonstruowania listy alfabetycznej dla spisu czonkw spoecznoci uywamy skadni:
<% @letters.each do |letter| %>
.
.
.
<% end %>

Jest to w Ruby kanoniczny sposb iteracji przez tablic, ale powiniene wiedzie, e
wewntrz widokw niektrzy programici Rails wykorzystuj skadni alternatywn:
<% for letter in @letters %>
.
.
.
<% end %>

Jest tak prawdopodobnie dlatego, e ich zdaniem taka skadnia bdzie bardziej zrozumiaa dla nie-programistw na przykad projektantw stron ktrzy maj
szans na ni natrafi.
Nic nam nie przeszkadza w skadni alternatywnej jest taka sama jak gwny konstrukt ptli w Pythonie, ktry uwielbiamy ale uycie each jest zdecydowanie bardziej w stylu Ruby: w tym jzyku zwykle do przesyania instrukcji do obiektw uywa
si metod7 w tym przypadku uywamy each, aby poinstruowa tablic, by zwracaa po kolei swoje elementy. Poniewa nie widzimy przekonujcego powodu, by
rozdziela style, pozostaniemy przy each nawet w widokach.
Naley podkreli, e nawiasy okrge wok { :action => "index", :id =>
letter } s niezbdne do wywoania link_to. Argumenty funkcji link_to maj
posta:
link_to(name, options = {}, html_options = nil)

Potrzebujemy nawiasw klamrowych, aby okreli, gdzie koczy si tablica asocjacyjna


z opcjami, a zaczyna tablica asocjacyjna z opcjami HTML. Gdybymy napisali
<%= link_to letter, :action = "index", :id => letter, :class =>
letter_class %>

caa tablica asocjacyjna


:action = "index", :id => letter, :class => letter_class

zostaaby przyjta jako options. W wyniku tego zamiast odnonikw w postaci


<a href="/community/index/A" class=letter">A</a>

Filozofia projektu, zwana przesyaniem komunikatw, jest w duej mierze inspirowana przez
Smalltalk.

338

RAILSSPACE

otrzymalibymy odnoniki w poniszej formie:


<a href="/community/index/A?class=letter">A</a>

a zupenie nie o to nam chodzi.


Aby uzyska dany wygld spisu spoecznoci, wykorzystamy niesamowite moliwoci CSS w nadawaniu stylu znacznikom zakotwiczenia (a). Wystarczy, e dodamy
ponisze reguy do pliku site.css:

LISTING 10.6. public/stylesheets/site.css


/* Style dla spoecznoci */
a, a#visited {
color: maroon;
text-decoration: none;
}
.letter, .letter_current {
width: 0.9em;
text-align: center;
border: 1px solid gray;
background: #fff;
padding: 5px 2px 1px 2px;
float: left;
margin: 2px
}
.letter:hover {
background: #fe4;
}
.letter_current {
background: #fe4;
font-weight: bold;
border: 1px solid black;
}

Strona spisu spoecznoci wyglda ju cakiem dobrze (rysunek 10.2), cho jeszcze tak
naprawd nic nie robi. Zajmijmy si teraz drug czci.

10.3.4. WYWIETLANIE WYNIKW INDEKSU


W punkcie 10.3.2 akcja index spoecznoci tworzya zmienn egzemplarza @users,
zawierajc uytkownikw do wywietlenia w widoku. Wykorzystamy t zmienn
w tabeli z wynikami, ktr umiecimy w pliku czci /app/views/community/_user_table.
rhtml. Najpierw musimy wywoa ten plik czci z pliku index.rhtml:

Rozdzia 10. SPOECZNO

339

RYSUNEK 10.2. Strona spoecznoci RailsSpace z adnie wystylizowanym indeksem


alfabetycznym
LISTING 10.7. app/views/community/index.rhtml
.
.
.
<%= render :partial => "user_table" %>

Ten plik bdzie tworzy tabel wynikw (jeeli bd jakie wyniki do wywietlenia)
poprzez iteracj przez zawarto zmiennej @users w celu utworzenia wiersza tabeli dla
kadego uytkownika:

LISTING 10.8. app/views/community/_user_table.rhtml


<% if @users and not @users.empty? %>
<table class="users" border="0" cellpadding="5" cellspacing="1">
<tr class="header">
<th>Imi i nazwisko</th> <th>Wiek</th> <th>Pe</th> <th>Miejsce
pobytu</th>
</tr>
<% @users.each do |user| %>
<tr class="<%= cycle('odd', 'even') %>">
<td><%= link_to user.name, profile_for(user) %></td>
<td><%= user.spec.age %></td>
<td><%= user.spec.gender %></td>
<td><%= user.spec.location %></td>
</tr>

340

RAILSSPACE

<% end %>


</table>
<% end %>

Zwr uwag, e uycie funkcji pomocniczej cycle, ktra (domylnie) zwraca raz jeden,
raz drugi argument8, sprawio, e przypisanie naprzemiennych stylw CSS jest banalne.
Zwr te uwag, e w wywoaniu link_to uylimy funkcji profile_url wygenerowanej przez regu trasowania, ktr wprowadzilimy w punkcie 9.1.1:

LISTING 10.9. config/routes.rb


map.connect 'profile/:screen_name', :controller = 'profile', :action
=> 'show'

Uylimy rwnie nowej metody name z modelu User, ktra zwraca imi i nazwisko
uytkownika, jeeli informacje te s dostpne, a w przeciwnym przypadku zwraca
pseudonim:

LISTING 10.10. app/models/user.rb


# Zwraca rozsdn nazw uytkownika
def name
spec.full_name.or_else(screen_name)
end

T funkcj mona rwnie wykorzysta w plikach app/views/user/index.rhtml (z punktu


9.4.4) oraz app/views/profile/show.rhtml (z podrozdziau 9.6). Jeeli chcesz, zastosuj je
w tych plikach.
Aby nasz plik czci dziaa, musimy zrobi jeszcze jedn rzecz doda metod age
do modelu Spec, aby @user.spec.age istniao:

LISTING 10.11. app/models/spec.rb


# Zwraca wiek obliczany na podstawie daty urodzenia
def age
return if birthdate.nil?
today = Date.today
if (today.month > birthdate.month) or
(today.month == birthdate.month and today.day >= birthdate.day)
# Urodziny ju byy w tym roku
today.year - birthdate.year
else
today.year - birthdate.year - 1
end
end

Bardziej wyrafinowane przykady zastosowania cycle znajdziesz w API Rails.

Rozdzia 10. SPOECZNO

341

W zasadzie ukoczylimy tworzenie funkcjonalnoci, co obrazuje rysunek 10.3, ale


strona nie wyglda adnie. Aby do wynikw wyszukiwania doda nieco stylu na
przykad naprzemienne stosowanie stylw dla wierszy na podstawie cycle dodaj
ponisze reguy do sekcji Style dla spoecznoci w pliku site.css:

RYSUNEK 10.3. Ostateczna posta spisu spoecznoci


LISTING 10.12. public/stylesheets/site.css
/* Style dla spoecznoci */
.
.
.
table.users {

342

RAILSSPACE

background: #fff;
margin-left: 2em;
}
table.users td.bottom {
border-top: 1px solid #999;
padding-top: 10px;
}
table.users th {
color: white;
background: maroon;
font-weight: normal;
}
table.users th a {
color: white;
text-decoration: underline;
}
table.users tr.even {
background: #ddd;
}
table.users tr.odd {
background: #eee;
}

Musimy wprowadzi jeszcze jedn drobn zmian, aby wszystko dziaao jak naley.
Trzeba zmieni funkcj tworzenia odnonika w pasku nawigacji w pliku pomocniczym
Application:

LISTING 10.13. app/helpers/application helper.rb


# Zwraca odnonik do wykorzystania w ukadzie nawigacji
def nav_link(text, controller, action="index")
link_to_unless_current text, :id => nil,
:action => action,
:controller => controller
end

Powd, dla ktrego to niezbdne, jest do subtelny. Bez jakiegokolwiek identyfikatora w wywoaniu linkt_to_unless_current Rails nie bdzie widzia rnicy midzy
/community/index a, powiedzmy, /community/index/A. W wyniku tego odnonik Spoeczno w pasku nawigacji nie bdzie wywietlany, dopki nie dodamy opcji :id => nil.
Musimy rwnie zmodyfikowa tras dla gwnej strony naszej witryny, aby wzi pod
uwag obecno identyfikatora nil:

Rozdzia 10. SPOECZNO

343

LISTING 10.14. config/routes.rb


.
.
.
# You can have the root of your site routed with map.root
# -- just remember to delete public/index.html.
map.connect '', :controller => 'site', :action => 'index', :id =>
nil
.
.
.

Dziki temu / wci bdzie automatycznie kierowao do /site/index.


Po zajciu si tym drobiazgiem ukoczylimy w kocu spis czonkw spoecznoci
(rysunek 10.4).

10.4. DOPRACOWYWANIE WYNIKW


W tej chwili tabela wietnie wywietla wyniki. Jest jednak kilka powszechnie stosowanych usprawnie, ktre poprawiaj wygld wynikw, gdy do wywietlenia jest
stosunkowo sporo uytkownikw. W tym podrozdziale pokaemy, jak atwo w Rails
mona utworzy paginacj wynikw, dziki czemu odnoniki do list uytkownikw bd
wygodnie podzielone na mniejsze czci. Dodamy rwnie pomocne podsumowanie
wynikw, wskazujce, jak wiele wynikw zostao odnalezionych. Jak moesz si spodziewa, utworzony w tym podrozdziale kod wykorzystamy pniej podczas implementacji wyszukiwania i przegldania.

10.4.1. DODAWANIE PAGINACJI9


Nasz spis czonkw spoecznoci powinien obsugiwa wiele stron wynikw, dziki
czemu mimo powikszania si liczby uytkownikw RailsSpace, bd one wci adnie
wywietlane. Zamierzamy wywietla jedn stron wynikw na raz i umieszcza odnoniki do kolejnych stron. Jest to czsto stosowany wzorzec przy wywietlaniu informacji w internecie, wic Rails dostarcza kilka funkcji pomocniczych uatwiajcych
implementacj tej funkcjonalnoci. W kontrolerze musimy jedynie zastpi wywoanie
find wywoaniem funkcji paginate. Skadnie tych funkcji s bardzo podobne
zmie tylko:

W Rails 2.0 wycofano funkcj paginate. Jest ona dostpna wycznie jako plugin classic_
pagination. W celu jej zainstalowania naley wpisa ruby script/plugin install svn://errthe
blog.com/svn/plugins/classic_pagination. Po przeprowadzeniu instalacji konieczne jest ponowne
uruchomienie serwera deweloperskiego przyp. tum.

344

RAILSSPACE

RYSUNEK 10.4. Strona po dodaniu stylw do tabeli wynikw


LISTING 10.15. app/controllers/community_controller.rb
specs = Spec.find(:all,
:conditions => ["last_name like ?", @initial+'%'],
:order => "last_name, first_name")

Rozdzia 10. SPOECZNO

345

na:

LISTING 10.16. app/controllers/community_controller.rb


@pages, specs = paginate(:specs,
:conditions => ["last_name like ?",
@initial+'%'],
:order => "last_name, first_name")

W miejsce :all funkcja paginate przyjmuje symbol reprezentujcy nazw tabeli, ale
pozostae dwie opcje s takie same. (Wicej opcji funkcji paginate znajdziesz w API
Rails). Podobnie jak Spec.find, funkcja paginate zwraca list specyfikacji, ale zwraca
te w zmiennej @pages list stron wynikw. Zwr uwag, e paginate zwraca dwuelementow tablic, wic moemy przypisa wartoci obu zmiennym jednoczenie,
korzystajc ze skadni Ruby dla wielokrotnych przypisa:
a, b = [1, 2] # a rwne 1, b rwne 2

Nie drcz si zbytnio, czym jest @pages. Przede wszystkim jest ona przesyana do funkcji
pagination_links w widoku, co za chwile uczynimy.
Bdziemy paginowa wyniki tylko wtedy, gdy zmienna @pages bdzie istniaa, a jej
warto bdzie wiksza ni jeden, dlatego te utworzymy krtk funkcj pomocnicz
testujc te warunki:

LISTING 10.17. app/helpers/application_helper.rb


module ApplicationHelper
.
.
.
# Zwraca true, jeeli wyniki powinny by podzielone na strony
def paginated?
@pages and @pages.length > 1
end
end

Poniewa spodziewamy si, e funkcja paginated? bdzie nam potrzebna w kilku


miejscach, umiecilimy j w gwnym pliku pomocniczym aplikacji.
Pozostao nam tylko umieci paginowane wyniki na kocu tabeli uytkownikw,
korzystajc ze wspomnianej wyej funkcji pomocniczej pagination_links:

LISTING 10.18. app/views/community/_user_table.rhtml


<% if @users and not @users.empty? %>
<table class="users" border="0" cellpadding="5" cellspacing="1">
.
.
.

346

RAILSSPACE

<% end %>


<% if paginated? %>
<tr>
<td colspan="4" align="right">
Strony: <%= pagination_links(@pages, :params => params) %>
</td>
</tr>
<% end %>
</table>
<% end %>

Wykorzystujemy tutaj funkcj pagination_links, ktra przyjmuje zmienn wygenerowan przez funkcj paginate i tworzy odnoniki dla wielu stron, co obrazuje
rysunek 10.5.

RYSUNEK 10.5. Spis alfabetyczny dzielony na strony

Rozdzia 10. SPOECZNO

347

Przy okazji przekazalimy do pagination_links zmienn params, korzystajc


z :params => params, dziki czemu funkcja bdzie moga wcieli przesane parametry do tworzonych adresw URL. W tej chwili nie bdziemy tego potrzebowa, ale
przyda si nam w rozdziale 11.

10.4.2. PODSUMOWANIE WYNIKW


Czsto przy zwracaniu wynikw wyszukiwania umieszcza si informacj o cakowitej
liczbie wynikw i jeeli wyniki s paginowane, informacje o tym, ktre elementy s
obecnie wywietlane. Innymi sowy, chcemy, aby wywietlana bya informacja podobna
do Znaleziono 15 wynikw. Wywietlani s uytkownicy od 1 do 10. Dodamy plik
czci implementujcy t funkcjonalno:

LISTING 10.19. app/views/community/_result_summary.rhtml


<% if @pages %>
<p>
Znaleziono <%= pluralize(@pages.item_count, "wynik", "wynikw") %>.
<% if paginated? %>
<% first = @pages.current_page.first_item %>
<% last = @pages.current_page.last_item %>
Wywietlani s uytkownicy <%= first %>&ndash;<%= last %>.
<% end %>
</p>
<% end %>

Nastpnie odwzorowujemy cz w widoku index:

LISTING 10.20. app/views/community/index.rhtml


.
.
.
<%= render :partial => "result_summary" %>
<%= render :partial => "user_table" %>

Jak widzimy na podstawie powyszego kodu, zmienna @pages zwracana przez funkcj
paginate ma kilka atrybutw uatwiajcych utworzenie takiego podsumowania:
item_count, ktry stanowi cakowit liczb wynikw, oraz current_page.first_item
i current_page.last_item, ktre stanowi numer pierwszego i ostatniego elementu
na stronie. Wyniki wygldaj teraz tak, jak to zapowiadalimy spjrz na rysunek 10.1.
Powinnimy rwnie zwrci uwag, e w pliku czci z podsumowaniem wynikw
wykorzystujemy rwnie wygodn funkcj pomocnicz Rails pluralize10:
10

Funkcja pluralize nie jest domylnie dostpna w sesji konsoli, wic musielimy j zawrze w sposb
jawny. Dowiedzielimy si, ktry modu naley zaadowa, przegldajc API Rails

348

RAILSSPACE

> ruby script/console


Loading development environment.
>> include ActionView::Helpers::TextHelper
=> Object
>> pluralize(0, "box")
=> "0 boxes"
>> pluralize(1, "box")
=> "1 box"
>> pluralize(2, "box")
=> "2 boxes"
>> pluralize(2, "box", "boxen")
=> "2 boxen"

Funkcja pluralize wykorzystuje inflektor Rails (wspomniany w punkcie 3.1.3) do okrelenia odpowiedniej formy liczby mnogiej danego acucha na podstawie pierwszego
argumentu, ktry okrela, ile jest obiektw. Jeeli chcesz przesoni inflektor, podaj trzeci
argument. W zwizku z tym w Rails nie ma wymwki dla tekstw w rodzaju Znaleziono 1 wynik(w) czy, nie daj Boe, Znaleziono 1 wynikw11.

11

Nonsensowne komunikaty 1 tests, 1 assertions, jakie moge zauway w wyjciu testw, s


win frameworku Ruby Test::Unit, a nie Rails.

You might also like