Professional Documents
Culture Documents
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
Wydawnictwo Helion
ul. Kociuszki 1c
44-100 Gliwice
tel. 032 230 98 63
e-mail: helion@helion.pl
SPIS TRECI
S PIS TRECI
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.
Rozdzia 4.
Rozdzia 5.
SPIS TRECI
5.3.
5.4.
5.5.
5.6.
Rozdzia 6.
RAILSSPACE
6.6.
Rozdzia 7.
Rozdzia 8.
SPIS TRECI
8.5.
Cz II
Rozdzia 9.
Rozdzia 10.
10
RAILSSPACE
10.4.
Rozdzia 11.
Rozdzia 12.
Rozdzia 13.
SPIS TRECI
13.2.2.
13.2.3.
13.2.4.
11
Rozdzia 14.
Rozdzia 15.
12
RAILSSPACE
Rozdzia 16.
Rozdzia 17.
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.
326
RAILSSPACE
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:
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.
327
328
RAILSSPACE
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)
(i podobnie dla zadania delete). Wiersz ten oznacza, e zadanie load zaley od rodowiska Rails. Rake odpowiada poprzez wczytanie lokalnego (deweloperskiego)
330
RAILSSPACE
Warto wspomnie, e kady z tych trzech elementw jest dostpny w zmiennej params.
Na przykad w tym przypadku params[:id] wynosi H.
331
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
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")
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]
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"])
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
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.
335
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"]
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
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.
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.
337
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)
Filozofia projektu, zwana przesyaniem komunikatw, jest w duej mierze inspirowana przez
Smalltalk.
338
RAILSSPACE
Strona spisu spoecznoci wyglda ju cakiem dobrze (rysunek 10.2), cho jeszcze tak
naprawd nic nie robi. Zajmijmy si teraz drug czci.
339
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:
340
RAILSSPACE
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:
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:
341
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:
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:
343
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
345
na:
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:
346
RAILSSPACE
Wykorzystujemy tutaj funkcj pagination_links, ktra przyjmuje zmienn wygenerowan przez funkcj paginate i tworzy odnoniki dla wielu stron, co obrazuje
rysunek 10.5.
347
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
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