Wydawnictwo Helion
ul. Koœciuszki 1c
44-100 Gliwice
tel. 032 230 98 63
e-mail: helion@helion.pl
Ajax on Rails
Autor: Scott Raymond
T³umaczenie: Adrian Elczewski
ISBN: 978-83-246-1048-8
Tytu³ orygina³u:
Ajax on Rails
Format: B5, stron: 336
Zobacz, jak wykorzystaæ potencja³ technologii Ajax i Rails
w tworzeniu zaawansowanych aplikacji internetowych!
•
Jak u¿ywaæ platformy Rails do budowy dynamicznych aplikacji internetowych?
•
Jak szybko tworzyæ witryny ajaksowe, wykorzystuj¹c wydajne biblioteki?
•
Jak zwiêkszyæ komfort pracy u¿ytkowników Twoich aplikacji internetowych?
Ajax to olbrzymie mo¿liwoœci w zakresie tworzenia dynamicznych i interaktywnych
aplikacji internetowych, dzia³aj¹cych niemal tak szybko, jak tradycyjne programy.
Jednak lepsza jakoϾ witryn wymaga zwykle pisania bardziej skomplikowanego kodu
i, co za tym idzie, wiêkszych nak³adów pracy i czasu. Tak te¿ by³o do niedawna
w przypadku Ajaksa, ale obecnie, gdy wzros³a popularnoœæ tej technologii, a ona sama
dojrza³a, programiœci mog¹ korzystaæ z wielu bibliotek i platform, dziêki którym
tworzenie efektownych aplikacji internetowych sta³o siê niezwykle proste.
„
Ajax on Rails
”
to podrêcznik dla programistów, którzy chc¹ szybko i ³atwo budowaæ
wydajne aplikacje internetowe na bazie dwóch popularnych mechanizmów – technologii
Ajax oraz platformy Rails. Czytaj¹c go, dowiesz siê, w jaki sposób Ajax umo¿liwia
kreowanie funkcjonalnych i wygodnych w obs³udze witryn, a tak¿e nauczysz siê
b³yskawicznie stosowaæ tê technologiê w oparciu o biblioteki Prototype i scipt.aculo.us
oraz kompletn¹ platformê do tworzenia aplikacji internetowych, czyli Rails. Poznasz te¿
sposoby sprawnego diagnozowania aplikacji ajaksowych oraz zapewnisz im
bezpieczeñstwo i wydajnoœæ, aby udostêpniaæ swym klientom produkty najwy¿szej klasy.
•
Przegl¹d mechanizmów technologii Ajax
•
Dzia³anie platformy Rails
•
Ajaksowe przesy³anie danych za pomoc¹ biblioteki Prototype
•
Dodawanie efektów do witryn przy u¿yciu biblioteki scipt.aculo.us
•
Generowanie kodu JavaScript za pomoc¹ szablonów RJS
•
Zwiêkszanie u¿ytecznoœci aplikacji
•
Diagnozowanie aplikacji na platformie Rails
•
Zapewnianie bezpieczeñstwa programu
•
Zwiêkszanie wydajnoœci aplikacji
3
Spis tre
ļci
Przedmowa .....................................................................................................................7
1. Wprowadzenie ..............................................................................................................11
Dla kogo jest ta ksiñĔka
11
Czym jest Ajax?
12
Czym jest Rails
18
„Twój Ajax w moim Rails”
21
Nabieranie prödkoĈci
21
Podsumowanie
27
2. Pierwsze kroki ..............................................................................................................29
Staromodny sposób
29
Prototype oraz inne biblioteki JavaScript
33
Rails pojawia siö na horyzoncie
35
Podsumowanie
40
3. Wprowadzenie do Prototype ....................................................................................... 41
Ustawianie sceny
41
ãñcza w Ajaksie
44
Formularze
48
Formularze w Ajaksie
51
Przyciski
52
Obserwatory formularza
54
Podsumowanie
55
4. Wprowadzenie do script.aculo.us ...............................................................................57
Efekty wizualne
57
Przeciñgnij i upuĈè
62
Podsumowanie
70
4
_ Spis treļci
5. RJS .................................................................................................................................. 71
Instrukcje zamiast danych
71
Umieszczenie R w skrócie RJS
72
Przykäady z Ĕycia wziöte
85
Podsumowanie
87
6. U
żytecznoļë Ajaksa ......................................................................................................89
Zasady uĔytecznoĈci
90
Kontekst Internetu
94
UĔytecznoĈè w Internecie
97
Programowanie uwzglödniajñce róĔne przeglñdarki
103
Podsumowanie
107
7. Testowanie i usuwanie b
ĥýdów .................................................................................109
Usuwanie bäödów
110
Testowanie
122
Podsumowanie
134
8. Bezpiecze
ħstwo .......................................................................................................... 135
Zdrowy sceptycyzm: nie ufaè danym wejĈciowym uĔytkownika
135
Hashowanie haseä
144
Uciszanie logów
145
Polityka tej samej domeny
146
UĔywanie i naduĔywanie metod HTTP
148
Szyfrowanie i certyfikaty bezpieczeþstwa
151
Lista mailingowa o bezpieczeþstwie w Rails
152
Podsumowanie
152
9. Wydajno
ļë ................................................................................................................... 153
ćrodowiska projektowe i produkcyjne
153
Przechowywanie sesji
154
Buforowanie wyjĈcia
155
Pakowanie zasobów
160
Postöpowanie z däugo dziaäajñcymi zadaniami
162
Podsumowanie
164
10. Informator o Prototype .............................................................................................. 165
Wsparcie Ajaksa
166
Manipulacja DOM
172
Wbudowane rozszerzenia
185
Spis tre
ļci _
5
11. Informator o script.aculo.us ....................................................................................... 199
Efekty wizualne
199
Przeciñgnij i upuĈè
209
Kontrolki
218
Rozszerzenia klasy element
226
Konstruktor DOM
228
Testowanie jednostkowe JavaScript
229
Metody narzödziowe
232
Przyk
ĥad A Quiz ...........................................................................................................233
Przyk
ĥad B Galeria zdjýë ............................................................................................ 249
Przyk
ĥad C Aplikacja wspóĥpracy w grupie ...............................................................267
Skorowidz ................................................................................................................... 315
29
ROZDZIA
Ĥ 2.
Pierwsze kroki
O, Ajaksie! ZnowuĔ Ciö przyzywam.
—
Sofokles
W tym rozdziale gäównym zamysäem jest zrobienie rundki, maäymi kroczkami, po naprawdö
prostych przykäadach wykorzystania technologii Ajax. Rails dostarcza wiele moĔliwoĈci two-
rzenia zäoĔonych interakcji w technologii Ajax z uĔyciem bardzo maäej iloĈci kodu. Ale Ĕeby
zrozumieè, co siö dzieje „pod maskñ”, kaĔdy powinien byè obeznany z najniĔszym pozio-
mem dziaäania technologii Ajax (np. obiektem
XMLHttpRequest
). Po przyswojeniu treĈci tej
ksiñĔki tworzenie obiektu
XMLHttpRequest
za pomocñ biblioteki Prototype lub bez jej uĔycia
nie bödzie stanowiäo problemu. Czytelnik bödzie potrafiä z pomocñ Rails utworzyè proste inte-
rakcje w technologii Ajax bez pisania jakiegokolwiek kodu w JavaScripcie. Z tym zaäoĔeniem
zdobödziemy wiedzö na temat dziaäania pomocników Rails oraz dowiemy siö, jak wielu käo-
potów one oszczödzajñ.
Dla czytelników, którzy mieli okazjö zapoznaè siö z Rails i znajñ podstawy Ajaksa, ten roz-
dziaä bödzie okazjñ do odĈwieĔenia wiedzy, warto przynajmniej przyjrzeè siö przykäadom.
Staromodny sposób
ēeby rozpoczñè, wykonajmy najprostszñ rzecz do zrobienia z uĔyciem technologii Ajax: klik-
nijmy äñcze i zaprezentujmy odpowiedĒ z serwera — uĔywajñc bezpoĈrednio
XMLHttpRequest
,
bez pomocy Prototype czy pomocników Rails dla JavaScript.
UĔywanie
XMLHttpRequest
jest czösto opisywane jako coĈ wyjñtkowo trudnego. ãatwo zauwa-
Ĕyè, Ĕe po zdobyciu odrobiny doĈwiadczenia i poznaniu kilku nowych koncepcji nie jest to aĔ
tak zawiäe, jak moĔna by byäo siö spodziewaè na podstawie powszechnej opinii.
Rozpoczynanie projektu
Osoby, które nie stworzyäy przykäadu szkieletu Rails w poprzednim rozdziale, powinny zrobiè
to teraz, wpisujñc w wierszu poleceþ systemowych:
rails ajaxonrails
cd ajaxonrails
script/server
30
_
Rozdzia
ĥ 2. Pierwsze kroki
Za pomocñ przeglñdarki naleĔy otworzyè stronö http://localhost:3000/ — powinien siö pojawiè ekran
powitalny Rails (dla celów przyszäego projektowania warto pamiötaè, Ĕe
script/server
uruchamia na porcie 3000 serwer HTTP). Teraz utwórzmy nowy kontroler, który nazwiemy
Chapter2Controller
, z akcjñ
myaction
. (Po uruchomieniu serwera w jednym terminalu
warto otworzyè inny).
script/generate controller chapter2 myaction
Generator Rails jest uĔywany do uzupeäniania szkieletu — przewaĔnie przez tworzenie
nowych kontrolerów i modeli. OczywiĈcie moĔna by w prosty sposób utworzyè
kontroler plików röcznie, ale uĔywanie generatora jest oszczödnoĈciñ pisania — co
zapobiega robieniu bäödów.
Generator ma takĔe inny skutek: za kaĔdym razem, gdy generuje siö kontroler, two-
rzony jest równieĔ wspóäpracujñcy z nim plik testów funkcjonalnych. To sposób Rails
na przypominanie, Ĕe testowanie jest waĔnñ czöĈciñ tworzenia aplikacji. Aby do-
wiedzieè siö wiöcej o dostöpnych generatorach i ich opcjach, naleĔy uruchomiè
script/generate bez Ĕadnych argumentów.
Teraz trzeba przejĈè do http://localhost:3000/chapter2/myaction. NaleĔy siö spodziewaè nowo utwo-
rzonego widoku jak na rysunku 2.1.
Rysunek 2.1. Nowo utworzony kontroler Rails i jego widok
Proszö zauwaĔyè, Ĕe domyĈlnie pierwsza czöĈè adresu URL determinuje kontroler, a druga akcjö
— metodö w ramach kontrolera. Teraz bödziemy edytowaè szablon dla tej akcji, do którego pro-
wadzi ĈcieĔka app/views/chapter2/myaction.rhtml. Dodajemy ten fragment HTML na dole pliku.
<p><a href="#" onclick="alert('Cze
Łð !');">Inline alert( )</a></p>
Jak moĔna zauwaĔyè, tworzymy akapit z prostym äñczem — ale zamiast standardowego atrybutu
href
uĔywamy
onclick
, do którego dostarczamy fragment kodu JavaScript do uruchomie-
nia. Po odĈwieĔeniu przeglñdarki i klikniöciu äñcza pojawi siö to, co przedstawia rysunek 2.2.
Wiöcej niĔ jedna czy dwie instrukcje wstawione do atrybutu
onclick
mogäyby szybko staè siö
niewygodne. PrzenieĈmy kod do osobnej funkcji JavaScript poprzez dodanie tego, co znaj-
duje siö poniĔej:
<p><a href="#" onclick="customAlert( ); ">Wywo
Īanie wĪasnej funkcji</a></p>
<script type="text/javascript">
function customAlert( ) {
alert('Powitanie z w
Ĩasnej funkcji.');
}
</script>
Staromodny sposób
_
31
Rysunek 2.2. Prosta ramka ostrzegawcza
Proszö spróbowaè ponownie odĈwieĔyè stronö i zobaczyè, co siö stanie. Rezultat powinien
byè w zasadzie taki sam jak poprzednio.
Koniec rozgrzewki, teraz zajmiemy siö Ajaksem. (Ale proszö pamiötaè, Ĕe wciñĔ zaglñdamy
„pod maskö” — pod koniec tego rozdziaäu sporo zäoĔonoĈci Rails znacznie siö uproĈci). Po
pierwsze, musimy zdefiniowaè nowñ akcjö w kontrolerze, app/controllers/chapter2_controller.rb.
Teraz znajduje siö tam akcja
myaction
, wiöc nastöpnñ nazwijmy
myresponse
. Aby to zrobiè,
naleĔy utworzyè nowy plik, myresponse.rhtml w katalogu app/views/chapter2. Do zawartoĈci
pliku wprowadĒmy:
Powitanie z serwera.
ēeby mieè pewnoĈè, Ĕe wszystko dziaäa, proszö odwiedziè tö akcjö w swojej przeglñdarce
pod adresem http://localhost:3000/chapter2/myresponse — bödzie widoczne to, co przedstawia
rysunek 2.3.
Rysunek 2.3. Wynik akcji myresponse
Teraz wróèmy do myaction.rhtml i dodajmy kolejny fragment kodu HTML i JavaScript.
<p><a href="#" onclick="serverSideAlert( );">Wywo
Īanie funkcji po stronie serwera
</a></p>
<script type="text/javascript">
function serverSideAlert( ) {
var request = new XMLHttpRequest( );
request.open('get', '/chapter2/myresponse', false);
request.send(null);
alert(request.responseText);
}
</script>
32
_
Rozdzia
ĥ 2. Pierwsze kroki
Za pomocñ przeglñdarki przejdĒmy z powrotem do http://localhost:3000/chapter2/myaction i klik-
nijmy nowe äñcze. JeĈli wszystko poszäo dobrze, powinna siö pojawiè wiadomoĈè z serwera,
taka jak na rysunku 2.4. Ostrzegamy, Ĕe ten przykäad nie bödzie dziaäaä we wczeĈniejszych niĔ
siódma wersjach Internet Explorera (ten problem podejmiemy póĒniej).
Rysunek 2.4. Rezultat pierwszego wywoäania w Ajaksie
Teraz do czegoĈ doszliĈmy! ēeby siö przekonaè, warto zerknñè na terminal, gdzie uruchomiony
jest
script/server
. Za kaĔdym razem, gdy klika siö „zajaksowane” äñcze, rejestrowane bö-
dzie nowe klikniöcie:
Processing Chapter2Controller#myresponse [GET]
Parameters: {"action"=>"myresponse", "controller"=>"chapter2"}
Completed in 0.00360 (278 reqs/sec) | Rendering: 0.00027 (7%) |
200 OK [http://localhost/chapter2/myresponse]
DuĔym problemem omawianego przykäadu jest to, Ĕe nie dziaäa on w jednej z najbardziej
rozpowszechnionych przeglñdarek, Internet Explorer 6. Przyczynñ jest obiekt ActiveX w im-
plementacji
XMLHttpRequest
Microsoftu (a wäaĈciwie dwa takie obiekty, co zaleĔy od wersji IE),
który musi byè tworzony w inny sposób. ēeby zlikwidowaè ten problem i sprawiè, aby nasz
przykäad dziaäaä poprawnie we wszystkich przeglñdarkach, tworzymy maäñ funkcjö. Oto wersja
przyjazna dla IE:
<p><a href="#" onclick="IEAlert( );">Wywo
Īanie serwera (dziaĪajîce pod IE)</a></p>
<script type="text/javascript">
function IEAlert( ) {
function getRequestObject( ) {
try { return new XMLHttpRequest( ) } catch (e) {}
try { return new ActiveXObject("Msxml2.XMLHTTP") } catch (e) {}
try { return new ActiveXObject("Microsoft.XMLHTTP") } catch (e) {}
return false
}
var request = getRequestObject( );
request.open('get', '/chapter2/myresponse', false);
request.send(null);
alert(request.responseText);
}
</script>
Ta wersja jest taka sama jak wczeĈniejsza, z wyjñtkiem tego Ĕe zamiast tworzyè bezpoĈrednio
obiekt
XMLHttpRequest
, wywoäywana jest funkcja
getRequestObject()
, która wybiera moĔ-
liwñ opcjö. Ta funkcja robi uĔytek z deklaracji
try
w JavaScripcie, która jest wykorzystywana
Prototype oraz inne biblioteki JavaScript
_
33
do wyäapywania wyjñtków i täumienia ich. (Ten przykäad wprowadza takĔe ideö deklarowa-
nia funkcji w funkcji, która moĔe byè nowoĈciñ dla niektórych programistów).
Dotychczas odrobinö oszukiwaliĈmy, poniewaĔ wywoäanie Ajaksa nie jest asynchroniczne.
Decyduje o tym trzeci parametr w metodzie
request.open()
. Do tej pory zakäadaliĈmy, Ĕe
wywoäanie nie byäo synchroniczne. W zwiñzku z tym
request.send()
byäo blokujñce — in-
terpreter JavaScript zatrzymywaä wykonywanie w tym wierszu i nie przechodziä do nastöpnego,
dopóki nie nadeszäa odpowiedĒ z serwera. ēeby sprawiè, aby wywoäanie byäo asynchroniczne,
musimy trochö zmieniè kod. Proszö dodaè ten fragment kodu do myaction.rhtml:
<p><a href="#" onclick="asyncAlert( )">Asynchroniczne wywo
Īanie serwera</a></p>
<script type="text/javascript">
function asyncAlert( ) {
function getRequestObject( ) {
try { return new XMLHttpRequest( ) } catch (e) {}
try { return new ActiveXObject("Msxml2.XMLHTTP") } catch (e) {}
try { return new ActiveXObject("Microsoft.XMLHTTP") } catch (e) {}
return false
}
var request = getRequestObject( );
request.open('get', '/chapter2/myresponse');
request.onreadystatechange = function( ) {
if(request.readyState == 4) alert(request.responseText);
}
request.send(null);
}
</script>
We wszystkich poprzednich przykäadach wywoäywaliĈmy
request.send()
i natychmiast po-
tem odwoäywaliĈmy siö do
request.responseText()
. Teraz, gdy wysyäamy asynchroniczne
Ĕñdanie, odpowiedĒ niekoniecznie wraca po zakoþczeniu wywoäania. Aby rozwiñzaè ten pro-
blem, obiekt
XMLHttpRequest
ma atrybut
readyState
, który zmienia siö w czasie cyklu Ĕycia
Ĕñdania. Ma takĔe atrybut
onreadystatechange
, gdzie moĔna zdefiniowaè funkcjö, która bö-
dzie wywoäywana za kaĔdym razem, gdy status
readyState
bödzie siö zmieniaä. W tym przy-
käadzie definiujemy funkcjö, która sprawdza, czy
readyState
jest równy
4
(co oznacza, Ĕe
Ĕñdanie siö zakoþczyäo; kody
readyState
opisane sñ w peäni w rozdziale 3.), a jeĈli tak, wy-
Ĉwietla okienko z komunikatem. Opanowanie asynchronicznych zdarzeþ moĔe wymagaè trochö
czasu, ale jest zasadniczñ czöĈciñ röcznego programowania w Ajaksie.
Prototype oraz inne biblioteki JavaScript
Osoby, które dopiero zaczynajñ swojñ przygodö z Ajaksem, prawdopodobnie zaczöäy zauwaĔaè,
Ĕe pisanie w czystym Ajaksie, pozbawionym wsparcia dodatkowych bibliotek albo metod
pomocniczych, nie jest powszechne. W ogóle pomysä pisania wiöcej niĔ tuzina wierszy kodu
w celu stworzenia najprostszego moĔliwego zadania jest odpychajñcy.
Dziesiñtki bibliotek JavaScript wychodzñ z siebie, Ĕeby sprawiè, by Ajax byä äatwiejszy w obsäu-
dze. Jednñ z najbardziej popularnych jest Prototype, która stanowi czöĈè Rails. Bödziemy oma-
wiaè Prototype gruntownie w rozdziale 10., ale teraz przyjrzyjmy siö pewnym przykäadom.
Zanim zaczniemy coĈ innego, przeróbmy ponownie ostatni przykäad, tym razem uĔywajñc
Prototype. Oto nowy fragment do dodania:
<script src="/javascripts/prototype.js" type="text/javascript">
</script>
<p><a href="#" onclick="prototypeAlert( );">Wywo
Īanie funkcji z Prototype</a></p>
34
_
Rozdzia
ĥ 2. Pierwsze kroki
<script type="text/javascript">
function prototypeAlert( ) {
new Ajax.Request('/chapter2/myresponse', { onSuccess: function(request) {
alert(request.responseText);
}})
}
</script>
Proszö zwróciè uwagö na pierwszy wiersz, gdzie wäñczamy äadowanie Ēródäa pliku prototype.js,
by móc z niego korzystaè na naszej stronie. Przy pierwszym tworzeniu szkieletu aplikacji Rails
kopia Prototype byäa umieszczona w katalogu public/javascripts. Wewnñtrz funkcji
prototype-
Alert()
pierwszy wiersz tworzy nowñ instancjö
Ajax.Request
, jednej z klas Prototype. Pierwszy
wywoäywany argument jest adresem URL, drugi — jest obiektem JavaScript — kolekcjñ par
kluczy – wartoĈci, które zachowujñ siö podobnie do map albo tablic asocjacyjnych w innych
jözykach programowania. W tym przypadku jedynñ wartoĈciñ jest
onSuccess
okreĈlajñca
funkcjö wywoäywanñ jako funkcja zwrotna.
Proszö zwróciè uwagö, iĔ w tym przykäadzie nie ma Ĕadnego kodu specyficznego dla obsäugi
wersji
XMLHttpRequest
dla przeglñdarki IE i Ĕadnej obsäugi kodów
readyState
. Prototype
obsäuguje te szczegóäy, udostöpniajñc programiĈcie duĔo czystsze API.
Dotychczas wszystkie nasze przykäady tworzyäy okno komunikatu
alert()
— które, w rze-
czywistych aplikacjach, prawdopodobnie nie jest najczöĈciej uĔywane. Znacznie czöĈciej do-
dawana jest nowa zawartoĈè strony albo modyfikowana dotychczasowa. Oto nowy fragment
do dodania:
<p><a href="#" onclick="updateElement( )">Uaktualnij element </a></p>
<p id="response"></p>
<script type="text/javascript">
function updateElement( ) {
new Ajax.Request('/chapter2/myresponse', { onSuccess: function(request) {
$('response').update(request.responseText);
}})
}
</script>
Proszö zauwaĔyè róĔnice miödzy powyĔszym a wczeĈniejszym przykäadem: dodany zostaä nowy
pusty element akapitu z atrybutem
id="response"
, który bödzie przechowywaä odpowiedĒ
otrzymanñ z serwera. Funkcja
onSuccess
zostaäa zmieniona, zamiast wywoäania
alert()
funkcja
ta umieszcza tekst odpowiedzi w elemencie
response
(uĔywajñc metody
update()
z biblio-
teki Prototype, która ustawia wäaĈciwoĈè elementu
innerHTML
). Symbol dolara jest faktycznie
nazwñ funkcji definiowanej przez Prototype, która pobiera ciñg znaków i zwraca element
HTML na podstawie tego ID. PoniewaĔ aktualizacja elementów HTML bödzie bardzo czösto
wykonywanym zadaniem, Prototype uäatwia to poprzez
Ajax.Updater.
Proszö to sprawdziè:
<p><a href="#" onclick="updater( )">Modernizuj za pomoc
î Ajax.Updater</a></p>
<p id="response2"></p>
<script type="text/javascript">
function updater( ) {
new Ajax.Updater('response2', '/chapter2/myresponse');
}
</script>
Funkcja $() w Prototype bödzie uĔywana bardzo czösto, z bliska wyglñda niezwy-
kle wartoĈciowo. Na pierwszy rzut oka jest prostym opakowaniem dla standardowej
metody DOM document.getElementById z nazwñ duĔo prostszñ do zapamiöta-
nia i sprawiajñcym wraĔenie skäadni JavaScript. Ale to wiöcej niĔ tylko opakowanie.
Rails pojawia si
ý na horyzoncie
_
35
Przede wszystkim moĔe przyjñè dowolnñ liczbö argumentów, wiöc moĔna otrzymaè
kilka elementów jednoczeĈnie. Ponadto kaĔdy zwracany element jest automatycznie
rozszerzany o potöĔny zestaw metod omówionych w rozdziale 10.
Prawdopodobnie najbardziej istotne jest, Ĕe jeĈli przekaĔe siö do metody $() ciñg
znaków, zwróci ona element DOM z tym wäaĈnie ID. Ale jeĈli przekaĔe siö obiekt ja-
kiegokolwiek innego typu — powiedzmy element DOM — w prosty sposób zwróci
ten obiekt bez zmian. Wynikiem jest to, Ĕe moĔna uĔywaè $() z wartoĈciami, nawet
jeĈli nie jest siö pewnym, czy wartoĈci te sñ ciñgiem znaków czy elementem DOM, co
sprawia, Ĕe API JavaScript jest mniej podatne na bäödy.
Proszö zwróciè uwagö, Ĕe ten przykäad nie ma w sobie funkcji
onSuccess
, tutaj
Ajax.Updater
pobiera tylko dwa argumenty: ID elementu HTML, który ma byè zaktualizowany, i URL Ĕñ-
dania.
Ajax.Updater
wywoäuje URL i automatycznie tworzy funkcjö
onComplete
säuĔñcñ do
zaktualizowania okreĈlonego elementu DOM za pomocñ wartoĈci
response.Text
. Tak jak
w przypadku
Ajax.Request
, ostatni argument jest zestawem opcji. Jedna z nich jest nazwana
insertion
. Pozwala na pójĈcie duĔo dalej niĔ prosta zamiana zawartoĈci elementu, zamiast
tego umoĔliwia wstawienie zawartoĈci w rozmaitych punktach. Istniejñ cztery typy wstawia-
nia:
Before
,
Top
,
Bottom
oraz
After
. Na przykäad:
<p><a href="#" onclick="appendToElement( )">Dodaj do elementu</a></p>
<p id="response3"></p>
<script type="text/javascript">
function appendToElement( ) {
new Ajax.Updater('response3', '/chapter2/myresponse',
{ insertion:Insertion.Bottom });
}
</script>
Kiedy kliknie siö äñcze za pierwszym razem, odpowiedĒ z serwera bödzie dodana do tej stro-
ny tak jak poprzednio. Przy póĒniejszych klikniöciach, zamiast zastñpiè wczeĈniejszñ zawar-
toĈè, kolejne odpowiedzi bödñ doäñczane do poprzednich.
Proszö zauwaĔyè, Ĕe zdoäaliĈmy zredukowaè doĈè zäoĔone zachowanie do postaci funkcji z za-
ledwie jednñ instrukcjñ. Aby zatoczyè peäne koäo, moĔemy zredukowaè kod do postaci poje-
dynczego atrybutu
onclick
:
<p><a href="#" onclick="new Ajax.Updater('response4',
'/chapter2/myresponse', { insertion:Insertion.Bottom });">
Dodaj do elementu</a></p>
<p id="response4"></p>
Jak bödzie moĔna siö wkrótce przekonaè, jest to dokäadnie ten sam kod, który generujñ pomoc-
niki JavaScript w Rails.
Rails pojawia si
ý na horyzoncie
Rails dostarcza dogodnñ integracjö z Prototype w formie metod pomocników, które generujñ
wywoäania funkcji udostöpnianych przez Prototype. Odkryjemy, jak tworzyè Ajaksa bez pi-
sania jakiegokolwiek kodu w JavaScripcie, uĔywajñc metody pomocnika
link_to_remote()
.
Po pierwsze, musimy cofnñè siö odrobinö i dowiedzieè siö, jak Rails obsäuguje widoki.
36
_
Rozdzia
ĥ 2. Pierwsze kroki
Podstawy ERb
Osoby, które kiedykolwiek korzystaäy z PHP, ColdFusion, ASP, JSP albo czegoĈ podobnego,
uznajñ, Ĕe jest to znajoma koncepcja. Wbudowany Ruby (Erb, ang. Embedded Ruby) pozwala
na äñczenie fragmentów Ruby z HTML-em. ERb definiuje zestaw specjalnych znaczników,
które sñ interpretowane jako Ruby; wszystko inne jest traktowane jako czysty HTML i zwra-
cane w nienaruszonej postaci. Oto te specjalne znaczniki:
<%= %>
Najcz
ýļciej używany, zawiera wyrażenie Ruby — którego wynik zwracany jest w miejscu znacznika.
<%= -%>
Dzia
ĥa tak jak powyższy, ale usuwa znaki nowego wiersza znajdujéce siý za tym znacznikiem, co pozwala na
czystsze zorganizowanie plików szablonów bez zb
ýdnych pustych miejsc w wynikowych dokumentach HTML.
<% %>
Przechowuje fragment kodu Ruby, ale nie zwraca niczego.
<% -%>
Dzia
ĥa tak jak powyższy, ale usuwa znaki nowego wiersza znajdujéce siý za tym znacznikiem.
<%# %>
To jest komentarz Ruby, który jest ignorowany i niczego nie zwraca.
Teraz spójrzmy na przykäad.
Czy pamiötasz dyskusjö o MVC z rozdziaäu 1.? Tutaj MVC zaczyna odgrywaè swojñ rolö.
Zwykle kontroler bödzie otrzymywaè Ĕñdanie wyĈwietlenia strony i przygotowywaè dane po-
trzebne dla widoku. W Rails dane te sñ umieszczane w zmiennych instancji (które sñ rozpoznawane
dziöki brzydkiemu znakowi
@
, od którego siö zaczynajñ ich nazwy). Proszö sobie zatem wy-
obraziè, Ĕe mamy takñ akcjö kontrolera:
def myaction
@foo = "Witaj,
Łwiecie!"
end
Akcja definiuje zmiennñ nazwanñ
@foo
i przypisuje jej äaþcuch znaków
Witaj,
Łwiecie!
. Nasz
szablon mógäby wiöc zawieraè coĈ takiego:
<%= @foo %>
I, gdy szablon jest wywoäywany,
<%= @foo %>
bödzie zastñpione przez
Witaj,
Łwiecie!
. Caä-
kiem oczywista sprawa. W praktyce przewaĔnie chce siö wykorzystaè zmiennñ w strukturze
HTML, np.:
<h1><%= @foo %></h1>
PoniewaĔ znacznik
<% %>
nie produkuje Ĕadnego wyjĈcia, najczöstsze jego uĔycie zwiñzane jest
ze strukturami kontrolnymi, takimi jak instrukcja
if
i iteracje
each
. W odróĔnieniu od innych
systemów szablonowych nie istnieje skäadnia specyficzna dla ERb dla tych konstrukcji; ERb
uĔywa zwyczajnych wyraĔeþ jözyka Ruby. Kilka przykäadów:
<% if @page_title %><h1><%= @page_title %></h1><% end %>
<% unless @names.empty? %>
<ul>
<% @names.each do |name| %><li><%= name %></li><% end %>
</ul>
<% end %>
Proszö spojrzeè na drugi wiersz. Zaczyna siö od wyraĔenia warunkowego
unless
— odpo-
wiednika Ruby dla
if not
. Proszö zwróciè teĔ uwagö na
@names.empty?
. Wszystkie tablice
Ruby korzystajñ z metody nazwanej
empty?
— zazwyczaj nazwy metod Ruby zwracajñcych
prawdö lub faäsz koþczñ siö znakiem zapytania. Ostatniñ sprawñ wartñ podkreĈlenia jest
czwarty wiersz. Wywoäanie metody
each
dla
@names
iteruje przez kaĔdy element tablicy, zatem
kod ten przejdzie caäñ tablicö
@names
i zwróci listö elementów w HTML dla kaĔdego imienia.
Rails pojawia si
ý na horyzoncie
_
37
Uk
ĥad graficzny
Ukäad graficzny tworzñ specjalne szablony, które przechowujñ powszechnie uĔywane znacz-
niki dla wielokrotnie wykorzystywanych widoków. W innych systemach szablonowych jest to
czösto osiñgane poprzez tworzenie plików z szablonami nagäówka i stopki, które sñ wäñczane
do szablonu strony. Rails dziaäa odwrotnie — nagäówki i stopki sñ zdefiniowane w jednym
pliku wystroju graficznego, a stamtñd doäñczana jest treĈè strony. Pliki ukäadu graficznego sñ
przechowywane w app/views/layouts i domyĈlnie Rails najpierw poszuka tego, którego nazwa
jest taka sama jak aktualnego kontrolera, np. chapter2.rhtml. JeĈli Rails takiego pliku ukäadu
graficznego nie znajdzie, poszuka pliku nazwanego application.rhtml. ZawartoĈè pliku wystroju
graficznego moĔe wyglñdaè nastöpujñco:
<html>
<head>
<title>Moja Aplikacja Rails </title>
<%= javascript_include_tag "prototype" %>
</head>
<body>
<%= yield %>
</body>
</html>
NajwaĔniejszñ czöĈciñ, o której naleĔy wspomnieè, jest
<%= yield %>
. Jej zadaniem jest doäñ-
czenie kodu z szablonu widoku. Innymi säowy, spowoduje wstawienie kodu szablonu widoku
do pliku ukäadu graficznego. Proszö nie zapominaè o doäñczeniu tego wywoäania w pliku ukäadu
graficznego, bo w przeciwnym razie strony mogñ siö wydawaè puste.
Cz
ýļci
CzöĈci sñ podszablonami zaprojektowanymi dla fragmentów zäoĔonych ze znaczników, które
wykorzystywane sñ ponownie — albo np. chce siö je trzymaè w osobnym pliku, Ĕeby pliki
szablonów pozostaäy przejrzyste. CzöĈci sñ äatwe do zidentyfikowania, poniewaĔ ich nazwy
zawsze zaczynajñ siö od znaku podkreĈlenia. Na przykäad, moĔna stworzyè plik app/views/
chapter2/_person.rhtml zawierajñcy:
<p><%= person.name %></p>
Z gäównego szablonu moĔna by byäo zaäñczyè takñ czöĈè:
<%= render :partial => "person" %>
Jest trochö magii wplecionej w przekazywanie zmiennych do czöĈci. PoniewaĔ ta czöĈè jest
nazwana „person”, gäówny szablon bödzie szukaä zmiennej instancji
@person
i przekazywaä jñ
do czöĈci jako zmiennñ lokalnñ
person
. Co jeĈli przykäadowa zmienna nie pasowaäaby do na-
zwy czöĈci? Wtedy trzeba jñ przekazaè jawnie jak tu:
<%= render :partial => "person", :locals => { :person => @adrian } %>
Wszystkie pary klucz – wartoĈè w tablicy asocjacyjnej
:locals
bödñ dostöpne jako zmienne
lokalne czöĈci.
DoĈè czöstym zastosowaniem czöĈci jest przeglñdanie tablicy obiektów i generowanie czöĈci
dla kaĔdego obiektu. Metoda
render
sprawia, Ĕe jest to proste dziöki opcji
:collection
. Na
przykäad:
<%= render :partial => "person", :collection => @people %>
38
_
Rozdzia
ĥ 2. Pierwsze kroki
W tym przykäadzie gäówny szablon zawiera tablicö
@people
, która bödzie przeglñdana, a kaĔdy
element tablicy — zmienna lokalna
person
— zostanie przekazany do czöĈci.
DomyĈlnie szablony czöĈci powinny znajdowaè siö w tym samym katalogu co szablon gäówny.
Aby wykorzystaè czöĈci z poziomu innych kontrolerów, wystarczy dodaè nazwö katalogu jako
przedrostek. Na przykäad:
<%= render :partial => "chapter1/person" %>
Pomimo Ĕe gäównym szablonem jest chapter2/index.rhtml, czöĈè bödzie generowana na podstawie
pliku chapter1/_person.rhtml.
Pomocniki
Pomocniki sñ prostymi metodami Ruby dostöpnymi w szablonach, dostarczajñcymi innego
sposobu na to, by szablon pozostaä czysty i czytelny. Dla kaĔdego kontrolera tworzony jest
jeden plik pomocnika, zatem
Chapter2Controller
bödzie powiñzany z plikiem app/helpers/
chapter2_helper.rb. JeĈli chce siö mieè pomocnika dostöpnego dla wszystkich kontrolerów, na-
leĔy zdefiniowaè go w application_helper.rb.
Rails dostarcza szereg wbudowanych pomocników, które sñ powszechnie uĔywane — wäaĈci-
wie juĔ widzieliĈmy kilka z nich. W czöĈci „Ukäad graficzny” powyĔej czwarty wiersz jest wy-
woäaniem pomocnika:
<%= javascript_include_tag "prototype" %>
javascript_include_tag()
jest metodñ Ruby zdefiniowanñ przez Rails, która pobiera jako ar-
gument äaþcuch znaków (albo tablicö äaþcuchów znaków) i zwraca fragment HTML, jak np.:
<script src="/javascripts/prototype.js" type="text/javascript"></script>
Innym uĔytecznym pomocnikiem jest
h
, który zamienia HTML na czysty tekst. Na przykäad,
<%= h @foo %>
zapobiegnie zwróceniu znaków specjalnych HTML w wyjĈciu, zamieniajñc je na
encje, co jest waĔnym posuniöciem ze wzglödów bezpieczeþstwa przy wyĈwietlaniu danych
wprowadzonych przez uĔytkownika. Implikacjö tö bödziemy rozwaĔaè dokäadniej w roz-
dziale 8.
Byè moĔe najczöĈciej uĔywanym pomocnikiem jest
link_to
, który w prosty sposób generuje
äñcze. Na przykäad:
<%= link_to "Kliknij tutaj", :url => "/chapter2/myresponse" %>
Ten pomocnik zwraca:
<a href="/chapter2/myresponse">Kliknij tutaj</a>
.
Jest to caäkiem trywialny przykäad, ale interesujñcñ sprawñ jest to, Ĕe zamiast przekazywania
zwykäego adresu URL jako parametru moĔna przekazaè nazwö kontrolera, nazwö akcji i inne
parametry — a URL zostanie odpowiednio skonstruowany. Wspaniaäe tutaj jest to, Ĕe gdy
zmienia siö ĈcieĔki aplikacji, äñcza automatycznie zostanñ zmienione tak, aby pasowaäy do
zmienionych ĈcieĔek.
<%= link_to "Kliknij tutaj", :action => "myresponse" %>
WyjĈcie tej wersji jest takie samo jak powyĔej. Proszö zauwaĔyè, Ĕe nie okreĈlaliĈmy nazwy kon-
trolera — zostaäa ona pominiöta. Rails domyĈla siö, Ĕe chcemy uĔyè tego samego kontrolera,
w którym wäaĈnie siö „znajdujemy”.