Cyfroteka.pl

klikaj i czytaj online

Cyfro
Czytomierz
00437 008411 10465762 na godz. na dobę w sumie
Rails. Receptury - książka
Rails. Receptury - książka
Autor: Liczba stron: 512
Wydawca: Helion Język publikacji: polski
ISBN: 978-83-246-1049-5 Data wydania:
Lektor:
Kategoria: ebooki >> komputery i informatyka >> webmasterstwo >> rails - programowanie
Porównaj ceny (książka, ebook, audiobook).

Zbiór gotowych rozwiązań dla twórców aplikacji internetowych

Dynamiczny rozwój sieci sprawia, że tradycyjne programy są stopniowo wypierane przez aplikacje sieciowe dostępne z poziomu przeglądarki internetowej -- wygodne, niezależne od systemu operacyjnego i łatwe w aktualizowaniu. Nadal jednak kluczowe znaczenie ma szybkość ich przygotowywania i modyfikowania. Dzięki zbiorom bibliotek zwanym 'frameworks' proces tworzenia takich produktów znacznie się skrócił -- umożliwia to programistom skoncentrowanie się na faktycznej funkcjonalności tworzonego narzędzia, ponieważ biblioteki te przejmują wiele typowych i wspólnych dla wszystkich aplikacji zadań. Wśród dostępnych w sieci narzędzi tego typu coraz większą popularność zyskuje Ruby on Rails, powoli stający się 'ikoną' nurtu Web 2.0. Tworzone za jego pomocą systemy są zwarte i łatwe do skalowania, a ich kod źródłowy jest przejrzysty i czytelny.

'Rails. Receptury' to zestaw porad i rozwiązań problemów, przed którymi stają programiści stosujący ten zbiór bibliotek w swojej pracy. Omówione tu zagadnienia przydadzą się zarówno początkującym, jak i doświadczonym twórcom aplikacji sieciowych. Przeczytasz tu o instalowaniu, konfigurowaniu i uruchamianiu środowiska Rails, połączeniach z bazami danych za pomocą ActiveRecord, generowaniu kodu HTML, zabezpieczaniu programów i tworzeniu kontrolerów odpowiadających za funkcjonalność systemu. Dowiesz się, jak wdrażać aplikacje Rails i korzystać w nich z możliwości oferowanych przez mechanizmy AJAX.

Skorzystaj ze sprawdzonych receptur i dołącz do twórców Web 2.0!

Znajdź podobne książki Ostatnio czytane w tej kategorii

Darmowy fragment publikacji:

Rails. Receptury Autor: Rob Orsini T‡umaczenie: £ukasz Piwko, Leszek Sagalara ISBN: 978-83-246-1049-5 Tytu‡ orygina‡u: Rails Cookbook Format: B5, stron: oko‡o 300 Zbi(cid:243)r gotowych rozwi„zaæ dla tw(cid:243)rc(cid:243)w aplikacji internetowych (cid:149) Instalacja i uruchomienie (cid:156)rodowiska Rails (cid:149) Przetwarzanie grafiki (cid:149) Korzystanie z technologii AJAX Dynamiczny rozw(cid:243)j sieci sprawia, ¿e tradycyjne programy s„ stopniowo wypierane przez aplikacje sieciowe dostŒpne z poziomu przegl„darki internetowej (cid:150) wygodne, niezale¿ne od systemu operacyjnego i ‡atwe w aktualizowaniu. Nadal jednak kluczowe znaczenie ma szybko(cid:156)(cid:230) ich przygotowywania i modyfikowania. DziŒki zbiorom bibliotek zwanym (cid:132)frameworks(cid:148) proces tworzenia takich produkt(cid:243)w znacznie siŒ skr(cid:243)ci‡ (cid:150) umo¿liwia to programistom skoncentrowanie siŒ na faktycznej funkcjonalno(cid:156)ci tworzonego narzŒdzia, poniewa¿ biblioteki te przejmuj„ wiele typowych i wsp(cid:243)lnych dla wszystkich aplikacji zadaæ. W(cid:156)r(cid:243)d dostŒpnych w sieci narzŒdzi tego typu coraz wiŒksz„ popularno(cid:156)(cid:230) zyskuje Ruby on Rails, powoli staj„cy siŒ (cid:132)ikon„(cid:148) nurtu Web 2.0. Tworzone za jego pomoc„ systemy s„ zwarte i ‡atwe do skalowania, a ich kod (cid:159)r(cid:243)d‡owy jest przejrzysty i czytelny. (cid:132)Rails. Receptury(cid:148) to zestaw porad i rozwi„zaæ problem(cid:243)w, przed kt(cid:243)rymi staj„ programi(cid:156)ci stosuj„cy ten zbi(cid:243)r bibliotek w swojej pracy. Om(cid:243)wione tu zagadnienia przydadz„ siŒ zar(cid:243)wno pocz„tkuj„cym, jak i do(cid:156)wiadczonym tw(cid:243)rcom aplikacji sieciowych. Przeczytasz tu o instalowaniu, konfigurowaniu i uruchamianiu (cid:156)rodowiska Rails, po‡„czeniach z bazami danych za pomoc„ ActiveRecord, generowaniu kodu HTML, zabezpieczaniu program(cid:243)w i tworzeniu kontroler(cid:243)w odpowiadaj„cych za funkcjonalno(cid:156)(cid:230) systemu. Dowiesz siŒ, jak wdra¿a(cid:230) aplikacje Rails i korzysta(cid:230) w nich z mo¿liwo(cid:156)ci oferowanych przez mechanizmy AJAX. (cid:149) Instalacja i uruchomienie (cid:156)rodowiska (cid:149) Komunikacja z bazami danych (cid:149) Wy(cid:156)wietlanie danych w przegl„darce (cid:149) Wykorzystywanie szablon(cid:243)w RHTML (cid:149) Generowanie kodu XML i RSS (cid:149) Przetwarzanie danych z formularzy (cid:149) Personalizacja narzŒdzi (cid:149) Korzystanie z JavaScript i AJAX (cid:149) Zabezpieczanie aplikacji Rails (cid:149) Optymalizacja aplikacji (cid:149) Wdra¿anie i utrzymywanie system(cid:243)w na serwerach (cid:149) Przetwarzanie obraz(cid:243)w Skorzystaj ze sprawdzonych receptur i do‡„cz do tw(cid:243)rc(cid:243)w Web 2.0! Wydawnictwo Helion ul. Ko(cid:156)ciuszki 1c 44-100 Gliwice tel. 032 230 98 63 e-mail: helion@helion.pl Spis treści Przedmowa .....................................................................................................................9 Wstęp ..............................................................................................................................11 1. Zaczynamy .................................................................................................................... 17 18 20 21 24 26 28 30 32 34 35 1.1. Społeczność Rails 1.2. Szukanie dokumentacji 1.3. Instalacja MySQL 1.4. Instalacja PostgreSQL 1.5. Instalacja Rails 1.6. Zmiana wersji Ruby i instalacja Rails w systemie OS X Tiger 1.7. Uruchamianie Rails w systemie OS X za pomocą Locomotive 1.8. Uruchamianie Rails w systemie Windows za pomocą Instant Rails 1.9. Aktualizacja Rails za pomocą RubyGems 1.10. Utworzenie repozytorium Subversion własnego projektu Rails 2. Praca w Rails .................................................................................................................39 39 41 45 2.1. Tworzenie projektu Rails 2.2. Rozpoczynamy pracę z rusztowaniami 2.3. Przyspieszanie Rails za pomocą serwera Mongrel 2.4. Zwiększanie możliwości produkcyjnych w systemie Windows za pomocą Cygwin 2.5. Wzorce pluralizacyjne w Rails 2.6. Praca w Rails w systemie OS X za pomocą TextMate 2.7. Wieloplatformowe tworzenie aplikacji z RadRails 2.8. Instalacja i uruchamianie Edge Rails 2.9. Uwierzytelnianie bezhasłowe za pomocą SSH 2.10. Tworzenie dokumentacji RDoc do własnej aplikacji Rails 2.11. Tworzenie w pełni funkcjonalnej aplikacji CRUD za pomocą Streamlined 47 48 51 53 54 56 57 60 3 3. Active Record ................................................................................................................65 66 69 71 75 78 81 82 85 88 91 95 98 102 106 110 113 117 120 122 123 125 3.1. Przygotowanie relacyjnej bazy danych do pracy z Rails 3.2. Programowe definiowanie schematu bazy danych 3.3. Zarządzanie bazą za pomocą migracji 3.4. Modelowanie bazy danych za pomocą Active Record 3.5. Kontrola relacji modelu z konsoli Rails 3.6. Dostęp do danych za pośrednictwem Active Record 3.7. Wyszukiwanie rekordów przy użyciu find 3.8. Iteracja na zestawie wyników Active Record 3.9. Wydajne pobieranie danych przy użyciu wczesnego wczytywania 3.10. Aktualizowanie obiektu Active Record 3.11. Wymuszanie spójności danych przy użyciu walidacji Active Record 3.12. Wykonywanie własnych zapytań za pomocą find_by_sql 3.13. Ochrona przed sytuacjami wyścigu za pomocą transakcji 3.14. Dodawanie do modelu możliwości sortowania przy użyciu acts_as_list 3.15. Wykonywanie zadań przy każdorazowym tworzeniu obiektów modelu 3.16. Modelowanie wątkowanego forum przy użyciu acts_as_nested_set 3.17. Tworzenie katalogu zagnieżdżonych tematów za pomocą acts_as_tree 3.18. Unikanie sytuacji wyścigu przy użyciu blokowania optymistycznego 3.19. Obsługa tabel z odziedziczoną konwencją nazewniczą 3.20. Automatyczny zapis sygnatur czasowych 3.21. Wydzielanie wspólnych relacji za pomocą powiązań polimorficznych 3.22. Połączenie modeli łączących i polimorfizmu w celu elastycznego modelowania danych 128 4. Action Controller ......................................................................................................... 133 134 137 138 139 141 143 144 146 147 149 151 153 154 155 4.1. Dostęp do danych formularza z kontrolera 4.2. Zmiana strony domyślnej aplikacji 4.3. Zwiększanie przejrzystości kodu za pomocą nazwanych tras 4.4. Konfigurowanie własnych zachowań wyboru tras 4.5. Wyświetlanie komunikatów alarmowych za pomocą flash 4.6. Przedłużanie okresu trwania komunikatu flash 4.7. Podążanie za akcjami za pomocą przekierowań 4.8. Dynamiczne generowanie adresów URL 4.9. Kontrolowanie żądań za pomocą filtrów 4.10. Rejestracja zdarzeń z wykorzystaniem filtrów 4.11. Renderowanie akcji 4.12. Ograniczanie dostępu do metod kontrolera 4.13. Wysyłanie do przeglądarki plików lub strumieni danych 4.14. Przechowywanie informacji o sesji w bazie danych 4 | Spis treści 4.15. Śledzenie informacji za pomocą sesji 4.16. Uwierzytelnianie z użyciem filtrów 157 160 5. Action View ................................................................................................................. 165 166 168 171 173 176 179 180 181 184 187 190 192 196 198 200 204 5.1. Upraszczanie szablonów za pomocą metod pomocniczych 5.2. Wyświetlanie obszernych zbiorów danych za pomocą stronicowania 5.3. Tworzenie lepkich list wyboru 5.4. Edycja relacji wiele-do-wielu za pomocą list wielokrotnego wyboru 5.5. Wyodrębnianie wspólnego kodu prezentacyjnego za pomocą makiet 5.6. Definiowanie domyślnej makiety dla aplikacji 5.7. Generowanie kodu XML za pomocą szablonów Builder 5.8. Generowanie źródeł RSS z danych Active Record 5.9. Ponowne wykorzystanie elementów za pomocą podszablonów 5.10. Przetwarzanie pól wejściowych tworzonych dynamicznie 5.11. Dostosowywanie zachowań standardowych metod pomocniczych 5.12. Tworzenie formularzy WWW z wykorzystaniem metod pomocniczych 5.13. Format daty, czasu i waluty 5.14. Personalizacja profili użytkowników za pomocą grawatarów 5.15. Unikanie szkodliwego kodu w widokach za pomocą szablonów Liquid 5.16. Globalizacja aplikacji Rails 6. Projektowanie z REST .................................................................................................209 211 216 218 221 224 227 6.1. Tworzenie zagnieżdżonych zasobów 6.2. Obsługa innych formatów danych za pomocą typów MIME 6.3. Modelowanie relacji REST przy użyciu modeli łączących 6.4. Poszerzanie możliwości CRUD za pomocą zasobów REST 6.5. Korzystanie ze złożonych zagnieżdżonych zasobów REST 6.6. Tworzenie aplikacji Rails zgodnie z REST 7. Testowanie aplikacji ...................................................................................................233 234 235 237 239 241 243 244 245 248 249 250 7.1. Centralizacja tworzenia obiektów wspólnych dla przypadków testowych 7.2. Tworzenie obiektów fixture dla przyporządkowań typu wiele-do-wielu 7.3. Importowanie danych testowych za pomocą obiektów fixture CSV 7.4. Dołączanie dynamicznych danych do obiektów fixture za pomocą ERb 7.5. Inicjalizacja testowej bazy danych 7.6. Interaktywne testowanie kontrolerów z poziomu konsoli Rails 7.7. Interpretacja danych z testu jednostkowego 7.8. Ładowanie danych testowych za pomocą obiektów fixture YAML 7.9. Monitorowanie testu pokrycia za pomocą zadania stats rake 7.10. Przeprowadzanie testów za pomocą narzędzia Rake 7.11. Przyspieszanie testów za pomocą transakcyjnych obiektów fixture Spis treści | 5 252 7.12. Sprawdzanie przez kontrolery za pomocą testów integracyjnych 255 7.13. Sprawdzanie kontrolerów za pomocą testów funkcjonalnych 258 7.14. Analiza zawartości pliku cookie 260 7.15. Testowanie tras własnych i nazwanych 262 7.16. Testowanie żądań HTTP za pomocą asercji związanych z odpowiedziami 263 7.17. Sprawdzanie modelu za pomocą testów jednostkowych 266 7.18. Jednostkowe testowanie walidacji modelu 268 7.19. Weryfikacja struktury DOM za pomocą asercji znaczników 271 7.20. Pisanie własnych asercji 7.21. Testowanie wysyłania plików 272 7.22. Modyfikowanie domyślnego zachowania klasy testującej przy użyciu makiet 275 277 7.23. Uzyskiwanie większej ilości danych dzięki ciągłemu uruchamianiu testów 7.24. Analiza pokrycia kodu za pomocą narzędzia Rcov 279 8. JavaScript i Ajax ......................................................................................................... 283 284 287 291 294 297 299 303 306 308 312 316 319 322 8.1. Dodawanie do strony elementów DOM 8.2. Tworzenie własnego raportu metodą przeciągnij i upuść 8.3. Dynamiczne dodawanie elementów do listy wyboru 8.4. Kontrolowanie ilości tekstu wprowadzanego do pola textarea 8.5. Aktualizowanie elementów strony za pomocą szablonów RJS 8.6. Wstawianie kodu JavaScript do szablonów 8.7. Umożliwianie użytkownikom zmiany kolejności elementów listy 8.8. Autouzupełnianie pól tekstowych 8.9. Wyszukiwanie i dynamiczne wyróżnianie tekstu 8.10. Uatrakcyjnianie interfejsu użytkownika przy użyciu efektów wizualnych 8.11. Implementacja wyszukiwarki Live Search 8.12. Edycja pól w miejscu 8.13. Tworzenie paska postępu w Ajaksie 9. Action Mailer ...............................................................................................................325 326 327 329 330 331 332 9.1. Konfiguracja Rails do wysyłania poczty 9.2. Tworzenie klasy mailera za pomocą generatora mailer 9.3. Formatowanie wiadomości e-mail przy użyciu szablonów 9.4. Dołączanie plików do wiadomości e-mail 9.5. Wysyłanie wiadomości e-mail z aplikacji Rails 9.6. Odbieranie poczty za pomocą mechanizmu Action Mailer 10. Debugowanie aplikacji Rails ......................................................................................335 336 338 10.1. Eksploracja Rails z poziomu konsoli 10.2. Naprawianie błędów u źródła przy użyciu opcji Ruby -cw 10.3. Debugowanie aplikacji w czasie rzeczywistym przy użyciu punktów wstrzymania 340 6 | Spis treści przy użyciu wbudowanej w Rails klasy Logger 10.4. Zapisywanie komunikatów do dziennika 10.5. Zapisywanie danych debugowania w pliku 10.6. Wysyłanie informacji o wyjątkach pocztą elektroniczną 10.7. Wyświetlanie w widokach informacji o środowisku 10.8. Wyświetlanie zawartości obiektów przy użyciu wyjątków 10.9. Filtrowanie zawartości dziennika rozwojowego w czasie rzeczywistym 10.10. Debugowanie połączenia HTTP przy użyciu rozszerzeń Firefoksa 10.11. Debugowanie kodu JavaScript w czasie rzeczywistym 10.12. Interaktywne debugowanie kodu za pomocą narzędzia ruby-debug przy użyciu powłoki JavaScript Shell 343 346 348 352 353 354 356 358 361 11. Bezpieczeństwo aplikacji ...........................................................................................365 365 367 369 370 372 11.1. Zabezpieczanie systemu za pomocą silnego hasła 11.2. Ochrona przed atakami typu SQL injection 11.3. Ochrona przed atakami typu cross-site scripting 11.4. Ograniczanie dostępu do publicznych metod i akcji 11.5. Zabezpieczanie serwera poprzez zamknięcie nieużywanych portów 12. Wydajność ...................................................................................................................375 376 378 380 383 12.1. Mierzenie wydajności serwera za pomocą narzędzia httperf 12.2. Testowanie wydajności fragmentów kodu aplikacji 12.3. Zwiększanie wydajności poprzez buforowanie statycznych stron 12.4. Okres ważności buforowanych stron 12.5. Mieszanie treści dynamicznej i statycznej przy użyciu mechanizmu 12.6. Filtrowanie buforowanych stron za pomocą buforowania akcji 12.7. Skracanie czasu dostępu do danych za pomocą systemu memcached 12.8. Zwiększanie wydajności poprzez buforowanie treści po przetworzeniu buforowania fragmentów 385 388 389 392 jako frontu dla Mongrel, Lighttpd i Apache 13. Hosting i wdrażanie ....................................................................................................395 396 397 400 13.1. Hosting Rails na serwerze Apache 1.3 i przy użyciu mod_fastcgi 13.2. Zarządzanie wieloma procesami Mongrel przy użyciu mongrel_cluster 13.3. Hosting Rails na Apache 2.2, mod_proxy_balancer i Mongrel 13.4. Wdrażanie Rails przy użyciu Pound 13.5. Dostosowywanie do własnych potrzeb rejestracji danych Pound 13.6. Konfiguracja Pound z obsługą SSL 13.7. Równoważenie obciążenia za pomocą prostego narzędzia o nazwie Pen 13.8. Wdrażanie projektu Rails przy użyciu Capistrano 13.9. Wdrażanie aplikacji w kilku środowiskach przy użyciu Capistrano za pomocą narzędzia cronolog 404 408 411 412 414 417 Spis treści | 7 13.10. Wdrażanie przy użyciu Capistrano bez dostępu do systemu Subversion 13.11. Wdrażanie przy użyciu Capistrano i mongrel_cluster 13.12. Wyłączanie strony podczas prac konserwacyjnych 13.13. Pisanie własnych zadań Capistrano 13.14. Usuwanie pozostałości po sesjach 419 421 423 426 430 14. Rozszerzanie Rails za pomocą wtyczek ................................................................... 433 434 435 437 440 443 448 453 455 457 14.1. Znajdywanie wtyczek 14.2. Instalowanie wtyczek 14.3. Manipulacja wersjami rekordów za pomocą wtyczki acts_as_versioned 14.4. Uwierzytelnianie przy użyciu wtyczki acts_as_authenticated 14.5. Upraszczanie znakowania za pomocą wtyczki acts_as_taggable 14.6. Rozszerzanie Active Record przy użyciu wtyczki acts_as 14.7. Dodawanie metod pomocniczych widoków do Rails jako wtyczek 14.8. Wysyłanie plików na serwer przy użyciu wtyczki file_column 14.9. Wysyłanie plików na serwer przy użyciu wtyczki acts_as_attachment 14.10. Wyłączanie rekordów zamiast ich usuwania 14.11. Dodawanie bardziej wyrafinowanego mechanizmu uwierzytelniania 461 463 za pomocą wtyczki acts_as_paranoid przy użyciu wtyczki login_engine 15. Grafika .........................................................................................................................467 467 471 475 476 479 481 484 15.1. Instalowanie interfejsu RMagick do przetwarzania obrazów 15.2. Wysyłanie obrazów do bazy danych 15.3. Serwowanie obrazków bezpośrednio z bazy danych 15.4. Tworzenie miniatur za pomocą RMagick 15.5. Generowanie dokumentów PDF 15.6. Wizualna prezentacja danych przy użyciu Gruff 15.7. Tworzenie małych grafów przy użyciu biblioteki Sparklines A Migracja do Rails 1.2 ...................................................................................................487 487 489 489 Action Controller Active Record Action View Skorowidz .................................................................................................................... 491 8 | Spis treści ROZDZIAŁ 5. Action View 5.0. Wprowadzenie Action View służy jako warstwa prezentacyjna lub warstwa widoku wzorca MVC (ang. model view controller). Oznacza to, że jest to składnik odpowiedzialny za obsługę szczegółów zwią- zanych z wyglądem naszej aplikacji Rails. Żądania przychodzące kierowane są do kontrole- rów, które z kolei generują szablony widoków. Szablony widoków mogą dynamicznie tworzyć dane wyjściowe do prezentacji w oparciu o struktury danych dostępne dla nich za pośred- nictwem powiązanych z nimi kontrolerów. To właśnie dzięki takiej dynamicznej prezentacji Action View pomaga rozdzielić szczegóły prezentacyjne od właściwej logiki biznesowej na- szej aplikacji. Rails wyposażony jest w trzy różnego rodzaju systemy szablonów widoków. O tym, który mechanizm szablonu zostanie zastosowany dla danego żądania, decyduje rozszerzenie pliku generowanego szablonu. Te trzy systemy szablonów oraz rozszerzenia plików wywołujące ich wykonanie to: szablony ERb (*.rhtml), szablony Builder::XmlMarkup (*.rxml) oraz szablo- ny JavaScriptGenerator lub RJS (*.rjs). Szablony ERb są najczęściej używane do generowania danych wyjściowych HTML aplikacji Rails; stosuje się je także do generowania wiadomości e-mail (choć tym zajmiemy się dopiero w rozdziale 9., „Action Mailer”). Składają się one z plików zakończonych rozszerzeniem .rhtml. Szablony ERb to połączenie HTML i zwykłego tekstu wraz ze specjalnymi znacznikami ERb, które osadzają w szablonach kod Ruby, np. kod ruby , = łancuch wyjściowy lub - kod ruby (z usuwaniem pustych znaków) - . Znak równości oznacza znacznik służący do wyprowadzenia łańcucha wynikowego jakiegoś wyrażenia Ruby. Znaczniki bez znaku równości oznaczają czysty kod Ruby i nie wytwarzają żadnych danych wyjściowych. Oto przykład prostego szablonu ERb tworzącego listę rozdziałów książki: ol for chapter in @chapters li = chapter.title /li end ol 165 Nasze szablony mogą ponadto zawierać inne szablony podrzędne dzięki przesłaniu opcji :file do metody render w znacznikach wyjściowych ERb, np.: = render :file = shared/project_calendar gdzie project_calendar.rhtml jest plikiem w katalogu współdzielonym wewnątrz głównego ka- talogu szablonów naszego projektu (app/views). W tym rozdziale przedstawię kilka popularnych technik efektywnego korzystania z szablo- nów ERb. Ponadto pokażę sposób generowania dynamicznego kodu XML za pomocą szablo- nów Builder::XmlMarkup, np. w celu wygenerowania źródeł RSS. Warto zauważyć, że choć szablony RJS są składnikiem Action View, to wstrzymam się z ich omówieniem aż do rozdzia- łu 8., „JavaScript i Ajax”. 5.1. Upraszczanie szablonów za pomocą metod pomocniczych Problem Szablony widoków służą do prezentacji — powinny one zawierać kod HTML i minimalną ilość dodatkowej logiki w celu wyświetlania danych z modelu. Chcemy oczyścić nasze sza- blony widoków z logiki programu, która mogłaby przeszkadzać w prezentacji. Rozwiązanie Definiujemy metody w module pomocniczym o nazwie odpowiadającej kontrolerowi, które- go widoki będą korzystać z tych metod. W tym przypadku tworzymy metody pomocnicze o nazwach display_new_hires i last_updated wewnątrz modułu o nazwie IntranetHelper (nazwanym tak od kontrolera Intranet). app/helpers/intranet_helper.rb: module IntranetHelper def display_new_hires hires = NewHire.find :all, :order = start_date desc , :limit = 3 items = hires.collect do |h| content_tag( li , strong #{h.first_name} #{h.last_name} /strong + - #{h.position} ( i #{h.start_date} /i ) ) end return content_tag( b , New Hires: ), content_tag( ul ,items) end def last_updated(user) { hr / br / i Ostatnia aktualizacja strony: #{Time.now}. Aktualizacji dokonał: #{user} /i } end end Wewnątrz widoku index kontrolera Intranet możemy wywoływać nasze metody pomocni- cze w taki sam sposób jak wszystkie inne metody systemowe. 166 | Rozdział 5. Action View app/views/intranet/index.rhtml: h2 Intranet - strona główna /h2 p Dopasuj kapelusz do głowy -- październik 2004. Jak stwierdził Larry Wall, informacja chce być wartościowa, a forma jej przedstawienia wpływa na jej wartość. W wydawnictwie O Reilly Media oferujemy wiele sposobów uzyskania informacji technicznych. Tim O Reilly mówi o tym w swoim kwartalnym liście dla O Reilly Catalog. /p = display_new_hires = last_updated( Goli ) Omówienie Metody pomocnicze są zaimplementowane w Rails w postaci modułów. Gdy Rails generuje kontroler, tworzy również moduł pomocniczy w katalogu app/helpers o nazwie odpowiadają- cej temu kontrolerowi. Domyślnie metody zdefiniowane w tym module dostępne są w wido- ku odpowiadającego mu kontrolera. Na rysunku 5.1 przedstawiono efekt wyjściowy widoku z użyciem metod pomocniczych display_new_hires i last_updated. Rysunek 5.1. Efekt końcowy widoku pomocniczego display_new_hires Jeśli chcemy współdzielić metody pomocnicze z innymi kontrolerami, musimy je wyraźnie zadeklarować w swoim kontrolerze. Jeżeli np. chcemy, aby metody z modułu IntranetHel- per były dostępne dla widoku kontrolera Store, należy do metody helper kontrolera Store przesłać opcję :intranet: class StoreController ApplicationController helper :intranet end 5.1. Upraszczanie szablonów za pomocą metod pomocniczych | 167 Teraz będzie ona szukać pliku o nazwie helpers/intranet_helper.rb i dołączy jego metody jako metody pomocnicze. Możemy również udostępnić dla widoku metody kontrolera jako metody pomocnicze — przesyłając nazwę metody kontrolera do metody helper_method. W poniższym przykładzie StoreController umożliwia wywołanie w naszym widoku = get_time w celu wy- świetlenia bieżącego czasu. class StoreController ApplicationController helper_method :get_time def get_time return Time.now end end Zobacz również Receptura 5.11, „Dostosowywanie zachowań standardowych metod pomocniczych”, Receptura 5.12, „Tworzenie formularzy WWW z wykorzystaniem metod pomocniczych”. (cid:129) (cid:129) 5.2. Wyświetlanie obszernych zbiorów danych za pomocą stronicowania Problem Wyświetlanie obszernych zbiorów danych w przeglądarce szybko może sprawić, że strona nie będzie się nadawać do wykorzystania, może nawet spowodować zawieszenie się przeglądar- ki. Patrząc od strony serwera, wczytywanie obszernych zbiorów danych w celu wyświetlenia jedynie kilku wierszy może mieć fatalny wpływ na wydajność. Chcemy zarządzać wyświe- tlaniem dużych zbiorów danych, stosując stronicowanie danych wyjściowych, czyli wyświe- tlanie podzbiorów wyjściowych na wielu stronach. Rozwiązanie Metoda pomocnicza paginate bardzo upraszcza konfigurację stronicowania. Aby przepro- wadzić stronicowanie danych wyjściowych składających się z obszernej listy filmów, należy wywołać metodę paginate w kontrolerze MoviesController i przechować wyniki w dwóch zmiennych egzemplarza o nazwach @movie_pages i @movies: app/controllers/movies_controller.rb: class MoviesController ApplicationController def list @movie_pages, @movies = paginate :movies, :order = year, title , :per_page = 10 end end 168 | Rozdział 5. Action View W naszym widoku przeprowadzamy iterację tablicy obiektów Movie przechowywanych w zmiennej egzemplarza @movies. Za pomocą obiektu Paginator w zmiennej @movie_pages utworzymy odnośniki do następnej i poprzedniej strony z wynikami. Do widoku dołączymy metodę pagination_links w celu wyświetlenia odnośników do pozostałych stron z wynikami. app/views/movies/list.xhtml: table width= 100 tr for column in Movie.content_columns th span style= font-size: x-large; = column.human_name /span /th end /tr for movie in @movies tr style= background: = cycle( #ccc , ) ; for column in Movie.content_columns td =h movie.send(column.name) /td end /tr end tr td colspan= = Movie.content_columns.length hr / center = link_to [poprzednia] , { :page = @movie_pages.current.previous } if @movie_pages.current.previous = pagination_links(@movie_pages) = link_to [następna] , { :page = @movie_pages.current.next } if @movie_pages.current.next /center /td /tr /table Omówienie Stronicowanie to standardowa technika używana przy wyświetlaniu obszernych zbiorów wynikowych w WWW. Rails obsługuje ten często spotykany problem przez łączenie danych w mniejsze zbiory przy użyciu metody pomocniczej paginate. Na rysunku 5.2 przedstawiono dane wyjściowe stronicowania na podstawie tego rozwiązania. Wywołanie w kontrolerze metody paginate zwraca obiekt Paginator, a także tablicę obiek- tów reprezentujących początkowy podzbiór wyników. Bieżąca strona określana jest przez za- wartość zmiennej params[ page ]. Jeśli ta zmienna nie występuje w obiekcie żądania, wów- czas domyślnie przyjmowana jest pierwsza strona. Opcje przesyłane do paginate określają obiekty modelu do pobrania oraz warunki zbioru wyników, który chcemy stronicować. W rozwiązaniu pierwszym argumentem przesłanym do paginate jest :movies, co nakazuje zwrócenie wszystkich obiektów filmów. Opcja :order określa ich kolejność. Opcja :per_page ustala maksymalną liczbę rekordów na każdej stronie z wynikami. Najczęściej wartość ta może zostać wybrana przez użytkownika. Aby sterować rozmiarem strony za pomocą parametru params[:page_size], należy wprowadzić następu- jący kod: 5.2. Wyświetlanie obszernych zbiorów danych za pomocą stronicowania | 169 Rysunek 5.2. Czwarta strona stronicowanej listy filmów def list if params[:page_size] and params[:page_size].to_i 0 session[:page_size] = params[:page_size].to_i elsif session[:page_size].nil? session[:page_size] ||= 10 end @movie_pages, @movies = paginate :movies, :order = year, title , :per_page = session[:page_size] end Za pomocą tego kodu adres URL http://localhost:3000/movies/list?page=2 page__size=30 ustawi rozmiar strony dla tej sesji na 30. Oprócz opcji :order, metoda paginate może korzystać ze wszystkich zwykłych opcji wy- szukiwania (np. :conditions, :joins, :include, :select) oraz dodatkowo z kilku rzadziej stosowanych. Zobacz również (cid:129) Dokumentacja API Rails dla ActionController::Pagination, http://api.rubyonrails.org/ classes/ActionController/Pagination.html. 170 | Rozdział 5. Action View 5.3. Tworzenie lepkich list wyboru Problem Skonfigurowaliśmy rusztowanie dla jednego z modeli i chcemy dodać listę wyboru, która dołącza informacje o powiązanym modelu do formularza edycji. Taka lista wyboru powinna pamiętać i wyświetlać wartość lub wartości wybrane w ostatnio wypełnianym formularzu. Rozwiązanie Mamy aplikację, która śledzi pewne zasoby i ich rodzaje. Poniższe definicje modeli ustana- wiają relacje pomiędzy zasobami i ich rodzajami: app/models/asset.rb: class Asset ActiveRecord::Base belongs_to :asset_type end app/models/asset_type.rb: class AssetType ActiveRecord::Base has_many :assets end Nasz widok będzie wymagać dostępu do wszystkich rodzajów zasobów w celu wyświetlenia listy wyboru. W kontrolerze pobieramy wszystkie obiekty AssetType i przechowujemy je w zmiennej egzemplarza o nazwie @asset_types: app/controllers/assets_controller.rb: class AssetsController ApplicationController def edit @asset = Asset.find(params[:id]) @asset_types = AssetType.find(:all) end def update @asset = Asset.find(params[:id]) if @asset.update_attributes(params[:asset]) flash[:notice] = Zasób został pomyślnie zaktualizowany. redirect to :action = show , :id = @asset else render :action = edit end end end W formularzu edycji należy utworzyć znacznik wyboru z atrybutem name, który przy wysy- łaniu formularza będzie dodawał asset_type_id do tablicy asocjacyjnej params. Korzystając z options_from_collection_for_select, utworzymy opcje listy wyboru na podstawie za- wartości @asset_types. 5.3. Tworzenie lepkich list wyboru | 171 app/views/assets/edit.rhtml: h1 Edycja zasobu /h1 form_tag :action = update , :id = @asset do = render :partial = form p select name= asset[asset_type_id] = options_from_collection_for_select @asset_types, id , name , @asset.asset_type.id /select /p = submit_tag Edit end = link_to Pokaż , :action = show , :id = @asset | = link_to Wstecz , :action = list Omówienie Rozwiązanie tworzy listę wyboru w widoku edycji zasobu, która zostaje zainicjowana wy- branym poprzednio asset_type. Metoda options_from_collection_for_select przyjmuje cztery parametry: zbiór obiektów, nazwę pola elementu listy stanowiącego wartość opcji, na- zwę pola elementu listy stanowiącego nazwę opcji oraz identyfikator rekordu elementu z listy, który powinien zostać wybrany domyślnie. Dlatego przesłanie @asset_type.id jako czwar- tego elementu sprawia, że poprzednio wybrany rodzaj zasobu staje się lepki (ang. sticky). Podobnie jak wiele innych metod pomocniczych w Action View, options_from_collection_ for_select jest po prostu otoczką bardziej ogólnej metody; w tym przypadku options_for_ select. Jest ona zaimplementowana wewnętrznie jako: def options_from_collection_for_select(collection, value_method, text_method, selected_value = nil) options_for_select( collection.inject([]) do |options, object| options [ object.send(text_method), object.send(value_method) ] end, selected_value ) end Dodajmy do widoku poniższy kod w celu wyświetlenia bieżącego rodzaju zasobu: p b Rodzaj zasobu: /b =h @asset.asset_type.name /p Na rysunku 5.3 przedstawiono wynikową listę wyboru z tego rozwiązania. Zobacz również Receptura 5.4, „Edycja relacji wiele-do-wielu za pomocą list wielokrotnego wyboru”. (cid:129) 172 | Rozdział 5. Action View Rysunek 5.3. Lepka lista wyboru w działaniu 5.4. Edycja relacji wiele-do-wielu za pomocą list wielokrotnego wyboru Problem Mamy dwa modele, między którymi zachodzi relacja typu wiele-do-wielu. Chcemy w wido- ku edycji jednego modelu utworzyć listę wyboru, która umożliwiałaby tworzenie powiązań z jednym lub większą liczba rekordów z drugiego modelu. Rozwiązanie Część systemu uwierzytelniania w naszej aplikacji umożliwia przypisanie użytkowników do jednej roli lub większej liczby ról o zdefiniowanych prawach dostępu. Relacja wiele-do-wielu między użytkownikami i rolami skonfigurowana jest za pomocą następujących definicji klas: app/models/user.rb: class User ActiveRecord::Base has_and_belongs_to_many :roles end app/models/role.rb: class Role ActiveRecord::Base has_and_belongs_to_many :users end 5.4. Edycja relacji wiele-do-wielu za pomocą list wielokrotnego wyboru | 173 W akcji edit kontrolera User dodajemy zmienną egzemplarza o nazwie @selected_roles i zapełniamy ją wszystkimi obiektami Role. Definiujemy metodę prywatną o nazwie handle_ roles_users w celu obsługi aktualizacji obiektu User o powiązane role z tablicy asocjacyjnej params. app/controllers/users_controller.rb: class UsersController ApplicationController def edit @user = User.find(params[:id]) @roles = {} Role.find(:all).collect {|r| @roles[r.name] = r.id } end def update @user = User.find(params[:id]) handle_roles_users if @user.update_attributes(params[:user]) flash[:notice] = Użytkownik został pomyślnie zaktualizowany. redirect_to :action = show , :id = @user else render :action = edit end end private def handle_roles_users if params[ role_ids ] @user.roles.clear roles = params[ role ids ].map { |id| Role.find(id) } @user.roles roles end end end W widoku edycji użytkownika za pomocą options_for_select tworzymy listę wielokrotne- go wyboru opcji w celu wygenerowania opcji z obiektów w zmiennej egzemplarza @roles. Tworzymy listę istniejących powiązań między rolami i przesyłamy ją jako drugi parametr. app/views/users/edit.xhtml: h1 Edycja użytkownika /h1 form_tag :action = update , :id = @user do = render :partial = form p select id= role_ids name= role_ids[] multiple= multiple = options_for_select(@roles, @user.roles.collect {|d| d.id }) /select /p = submit_tag Edit end = link_to Pokaż , :action = show , :id = @user | = link_to Wstecz , :action = list 174 | Rozdział 5. Action View Aby wyświetlić role przypisane do każdego użytkownika, łączymy je w postaci listy rozdzie- lonej przecinkami w widoku akcji show: app/views/users/show.rhtml: for column in User.content_columns p b = column.human_name : /b =h @user.send(column.name) /p end p b Rola (role): /b =h @user.roles.collect {|r| r.name}.join( , ) /p = link_to Edycja , :action = edit , :id = @user | = link_to Wstecz , :action = list Omówienie W Rails istnieją pewne metody umożliwiające przekształcanie zbioru obiektów w listy wybo- ru. Przykładowo metody select lub select_tag kontrolera ActionView::Helpers::Form- OptionsHelper generują cały znacznik wyboru HTML w oparciu o zbiór opcji. Większość z tych metod pomocniczych generuje tylko listę opcji. Na rysunku 5.4 możemy zobaczyć dwie wybrane dla użytkownika role oraz sposób ich przed- stawienia w widoku akcji show. Rysunek 5.4. Formularz umożliwiający wybór wielu elementów z listy wyboru 5.4. Edycja relacji wiele-do-wielu za pomocą list wielokrotnego wyboru | 175 Zobacz również (cid:129) (cid:129) Więcej informacji na temat metod wyboru w Rails znajduje się pod adresem pod adresem http://api.rubyonrails.org/classes/ActionView/Helpers/FormOptionsHelper.html, Receptura 3.0, „Wprowadzenie”, zawierająca omówienie tabel łączących używanych w za- rządzaniu relacjami wiele-do-wielu. 5.5. Wyodrębnianie wspólnego kodu prezentacyjnego za pomocą makiet Problem Sporo witryn WWW składających się z wielu stron zawiera wspólne elementy wizualne, któ- re pojawiają się na większości stron witryny (bądź nawet na wszystkich). Chcemy wyodrębnić ten wspólny kod prezentacyjny i uniknąć zbędnego powtarzania się w szablonach widoków. Rozwiązanie W katalogu app/views/layouts utworzymy plik makiety (ang. layout) zawierający elementy pre- zentacyjne, które mają być wyświetlane we wszystkich szablonach generowanych przez okre- ślony kontroler. Nazwijmy ten plik zgodnie z nazwą kontrolera, do którego szablonów ma on zostać użyty. W pewnym miejscu tego pliku umieścimy wywołanie do yield w celu wy- słania zawartości kodu, do którego ma zostać zastosowana makieta. app/views/layouts/main.rhtml: !DOCTYPE html PUBLIC -//W3C//DTD XHTML 1.0 Transitional//EN http://www.w3.org/TR/xhtml:/DTD/xhtml1-transitional.dtd html xmlns= http://www.w3.org/1999/xhtml xml:lang= en lang= en head meta http-equiv= content-type content= text/html;charset=utf-8 / = stylesheet link_tag main title Jakaś witryna CSS /title /head body div id= header h1 Treść nagłówka... /h1 /div div id= leftcol h3 Nawigacja: /h3 ul li a href= /main/ Strona główna /a /li li a href= /sales/ Sprzedaż /a /li li a href= /reports/ Raporty /a /li li a href= /support/ Obsługa /a /li /ul /div div id= maincol = yield /div 176 | Rozdział 5. Action View div id= footer p Tutaj umieszczamy tekst stopki... /p /div /body /html Po utworzeniu i umieszczeniu we właściwym miejscu pliku makiety main.rhtml każdy plik szablonu z katalogu app/views/main/ będzie otoczony przez zawartość makiety, np. poniższy plik index.rhtml zastąpi wywołanie yield w pliku makiety. app/views/main/index.rhtml: h2 Czym jest Web 2.0 /h2 p Załamanie rynku internetowego, do którego doszło jesienią 2001 roku, wyznaczyło punkt zwrotny sieci WWW. Wiele osób doszło do wniosku, że WWW było przereklamowane, podczas gdy gwałtowne wzrosty i wiążące się z tym załamania wydają się być wspólną cechą wszystkich rewolucji technologicznych. Zazwyczaj takie załamania wyznaczają punkt, w którym dominująca technologia jest już gotowa do zajęcia swego miejsca na scenie. Pretendenci zostają wykopani, a prawdziwe historie sukcesów pokazują siłę pozostałych. Tak pojawia się zrozumienie, w czym ci pierwsi różnią się od tych drugich. /p Zauważmy, że plik makiety zawiera wywołanie do stylesheet_link_tag main , wysyłają- ce znacznik dołączenia skryptu dla poniższego pliku CSS, który rozmieszcza różne elementy strony. public/stylesheets/main.css: body { margin: 0; padding: 0; color: #000; width: 500px; border: 1px solid black; } #header { background-color: #666; } #header h1 { margin: 0; padding: .5em; color: white; } #leftcol { float: left; width: 120px; margin-left: 5px; padding-top: 1em; margin-top: 0; } #leftcol h3 { margin-top: 0; } #maincol { margin-left: 125px; margin-right: 10px; } #footer { clear: both; background-color: #ccc; padding: 6px; } Omówienie Domyślnie jeden plik makiety odpowiada każdemu kontrolerowi naszej aplikacji. Rozwiązanie konfiguruje makietę dla aplikacji z kontrolerem Main. Domyślnie widoki generowane przez kontroler Main stosują makietę main.rhtml. Na rysunku 5.5 przedstawiono dane wyjściowe makiety dla zawartości szablonu index.rhtml, z użyciem arkusza stylów main.css. 5.5. Wyodrębnianie wspólnego kodu prezentacyjnego za pomocą makiet | 177 Rysunek 5.5. Typowa strona WWW z czterema obszarami, utworzona z wykorzystaniem makiet Za pomocą metody layout możemy wyraźnie zadeklarować, z której makiety kontroler po- winien korzystać. Jeśli np. chcemy, aby kontroler Gallery używał tej samej makiety, co kon- troler Main, powinniśmy dodać poniższe wywołanie makiety do definicji klasy kontrolera: class GalleryController ApplicationController layout main ... end Metoda layout akceptuje także dodatkowe opcje. Aby użyć makiety do wszystkich akcji z wy- jątkiem popup, należy zastosować: layout main , :except = :popup Dodatkowo zmienne egzemplarza zdefiniowane w akcji są dostępne wewnątrz widoku wy- generowanego w oparciu o tę akcję oraz szablonu makiety użytego do tego widoku. W starszych projektach można spotkać się z następującą składnią zamiast nowszej yield: = @content_for_layout Obie pełnią to samo zadanie, dołączając treść do szablonu. 178 | Rozdział 5. Action View Zobacz również Receptura 5.6, „Definiowanie domyślnej makiety dla aplikacji”. (cid:129) 5.6. Definiowanie domyślnej makiety dla aplikacji Problem Chcemy utworzyć jednolitą szatę graficzną w całej aplikacji za pomocą pojedynczego szablo- nu makiety. Rozwiązanie Aby zastosować jedną domyślną makietę do każdego widoku kontrolera, należy utworzyć szablon makiety o nazwie application.rhtml i umieścić go w katalogu z makietami naszej apli- kacji (app/views/layouts), np.: app/views/layouts/application.rhtml. !DOCTYPE html PUBLIC -//W3C//DTD XHTML 1.0 Transitional//EN http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd html xmlns= http://www.w3.org/1999/xhtml title Mój internetowy blog /title head meta http-equiv= Content-Type content= text/html; charset=IS0-8859-2 / = stylesheet_link_tag weblog = javascript_include_tag :defaults /head body div id= container = yield /div /body /html Omówienie Ogólny aplikacyjny szablon makiety z tego rozwiązania będzie domyślnie stosowany do wszyst- kich naszych widoków. Możemy spowodować pominięcie takiego zachowania dla określone- go kontrolera (a nawet dla akcji), tworząc dodatkowe pliki makiet o nazwach pochodzących od nazw naszych kontrolerów lub jawnie wywołać metodę layout w obrębie definicji klasy kontrolera. Zobacz również Receptura 5.5, „Wyodrębnianie wspólnego kodu prezentacyjnego za pomocą makiet”. (cid:129) 5.6. Definiowanie domyślnej makiety dla aplikacji | 179 5.7. Generowanie kodu XML za pomocą szablonów Builder Problem Zamiast generować pliki HTML za pomocą ERb, chcemy wygenerować kod XML lub XHTML. I raczej nie mamy ochoty na samodzielne wpisywanie wszystkich jego znaczników. Rozwiązanie Aby w Rails zbudować szablon Builder, należy utworzyć plik o rozszerzeniu .rxml. Plik ten trzeba umieścić w katalogu views. Przykładowo poniższy szablon Builder generowany jest w momencie wywołania akcji show kontrolera DocBook. app/views/docbook/show.rxml: xml.instruct! xml.declare! :DOCTYPE, :article, :PUBLIC, -//0ASIS//DTD DocBook XML V4.4//EN, http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd xml.article do xml.title ( Czym jest Web 2.0 ) xml.section do xml.title( Wzorce projektowe i modele biznesowe dla oprogramowania następnej generacji ) xml.para( Załamanie rynku internetowego, do którego doszło jesienią 2001 roku, wyznaczyło punkt zwrotny sieci WWW. Wiele osób doszło do wniosku, że WWW było przereklamowane, podczas gdy gwałtowne wzrosty i wiążące się z tym załamania wydają się być wspólną cechą wszystkich rewolucji technologicznych. Zazwyczaj takie załamania wyznaczają punkt, w którym dominująca technologia jest już gotowa do zajęcia swego miejsca na scenie. Pretendenci zostają wykopani, a prawdziwe historie sukcesów pokazują siłę pozostałych. Tak pojawia się zrozumienie, w czym ci pierwsi różnią się od tych drugich. ) end end Omówienie Po wywołaniu akcji show kontrolera DocBook rozwiązanie generuje następujące dane wyjściowe: ?xml version= 1.0 encoding= UTF-8 ? !DOCTYPE article PUBLIC -//OASIS//DTD DocBook XML V4.4//EN http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd article title Czym jest Web 2.0 /title section title Wzorce projektowe i modele biznesowe dla oprogramowania następnej generacji /title para Załamanie rynku internetowego, do którego doszło jesienią 2001 roku, wyznaczyło punkt zwrotny sieci WWW. Wiele osób doszło do wniosku, że WWW było przereklamowane, podczas gdy gwałtowne wzrosty i wiążące się z tym załamania wydają się być wspólną cechą wszystkich rewolucji technologicznych. Zazwyczaj takie załamania wyznaczają punkt, w którym dominująca technologia jest już gotowa do zajęcia swego miejsca na scenie. Pretendenci zostają wykopani, a prawdziwe historie sukcesów pokazują siłę pozostałych. Tak pojawia się 180 | Rozdział 5. Action View zrozumienie, w czym ci pierwsi różnią się od tych drugich. /para /section /article Szablony Builder działają na zasadzie przekształcania wywołań metod na obiekcie Builder:: XmlMarkup w znaczniki obejmujące pierwszy argument tego obiektu. Pozostałe opcjonalne argumenty są tablicą asocjacyjną, która jest interpretowana jako atrybuty tworzonego znacz- nika. Oto przykład: xml = Builder::XmlMarkup.new xml.h1( Ruby on Rails , {:class = framework }) Ten kod wygeneruje następujący znacznik: h1 class= framework Ruby on Rails /h1 W Rails szablony Builder są dostarczane automatycznie za pomocą obiektu Builder::XmlMarkup o nazwie xml, więc nie ma tu potrzeby tworzenia egzemplarza. Pierwszy parametr jest prze- syłany wspólnie jako blok, dzięki czemu tworzenie zagnieżdżonych znaczników staje się łatwe i czytelne. Oto przykład elementów podrzędnych utworzonych w obrębie elementu macierzy- stego przy użyciu składni blokowej: xml.h1 do xml.comment! z niewielkim naciskiem na Ruby... xml.span( Ruby , :style = color: red; ) xml.text! on Rails! end Ten szablon wytworzy: h1 !-- z niewielkim naciskiem na Ruby... -- span style= color: red; Ruby /span on Rails! /h1 Metody comment! i text! mają szczególne znaczenie; nie są one interpretowane jak nazwy znaczników, lecz tworzą odpowiednio komentarze XML lub zwykły tekst. Zauważmy, że na- zwy tych metod nie odpowiadają konwencji nazewniczej Ruby, zgodnie z którą metody „de- strukcyjne”, czyli modyfikujące obiekt bazowy (np. metody gsub! lub strip! klasy String), zakończone są znakiem !. Te metody tworzą jedynie dane wyjściowe, nie modyfikując obiek- tu bazowego. Zobacz również (cid:129) Więcej informacji na temat szablonów Builder znajduje się na witrynie projektu Rubyforge, pod adresem http://builder.rubyforge.org. 5.8. Generowanie źródeł RSS z danych Active Record Problem Chcemy, aby nasza aplikacja umożliwiała publikowanie danych z jej modelu w postaci źró- dła RSS (ang. Really Simple Syndication). Załóżmy np., że mamy bazę danych z informacjami o produktach. Są to dane ulegające częstym zmianom; chcemy zaoferować klientom wygodny sposób umożliwiający śledzenie tych zmian na bieżąco. 5.8. Generowanie źródeł RSS z danych Active Record | 181 Rozwiązanie Tworzenie źródła RSS odbywa się za pomocą akcji generującej w locie RSS w formacie XML przy użyciu szablonów Builder. Załóżmy, że mamy następujący schemat, który definiuje ta- belę z książkami. Każdy rekord zawiera informacje o sprzedaży, które często się zmieniają. db/schema.rb: ActiveRecord::Schema.define() do create_table books , :force = true do |t| t.column title , :string, :limit = 80 t.column sales_pitch , :string t.column est_release_date , :date end end W kontrolerze XmlController tworzymy akcję o nazwie rss, zbierającą informacje z modelu Book do zmiennej egzemplarza, która będzie używana przez szablon Builder: app/controllers/xml_controller.rb: class XmlController ApplicationController def rss @feed_title = Książki wydawnictwa O Reilly @books = Book.find(:all, :order = est_release_date desc , :limit = 2) end end W widoku powiązanym z akcją rss stosujemy konstrukcje znaczników XML szablonu Builder w celu utworzenia źródła RSS w formacie XML, na które składać się będzie zawartość zmien- nych egzemplarza @feed_title i @books. app/views/xml/rss.rxml: xml.instruct! :xml, :version= 1.0 , :encoding= UTF-8 xml.rss( version = 2.0 ) do xml.channel do xml.title @feed_title xml.link(request.protocol + request.host_with_port + url_for(:rss = nil)) xml.description(@feed_title) xml.language en-us xml.ttl 40 # Przykład daty i czasy według RFC-822: Tue, 10 Jun 2003 04:00:00 GMT xml.pubDate(Time.now.strftime( a, d b Y H: M: S Z )) @books.each do |b| xml.item do xml.title(b.title) xml.link(request.protocol + request.host_with_port + url_for(controller = posts , :action = show , :id = b.id)) xml.description(b.sales_pitch) xml.guid(request.protocol + request.host_with_port + url_for(:controller = posts , :action = show , :id = b.id)) end end end end 182 | Rozdział 5. Action View Omówienie Źródła RSS pozwalają użytkownikom na bieżąco śledzić częste aktualizacje witryny za pomo- cą agregatora źródeł RSS, np. NetNewsWire lub rozszerzenia Sage do przeglądarki Firefox. Wykorzystanie źródeł RSS i agregatorów znacznie ułatwia nadążanie za dużą ilością stale zmieniających się informacji. Źródła RSS zazwyczaj składają się z tytułu i krótkiego opisu, do którego załączony jest odnośnik do pełnej treści dokumentu opisywanego w danym elemencie. Pierwszy wiersz w szablonie rss.rxml tworzy deklarację XML, która określa wersję XML oraz zastosowane w dokumencie kodowanie znaków. Następnie tworzony jest element główny, zawierający w sobie wszystkie pozostałe elementy. Elementy wiadomości RSS generowane są przez wykonywanie pętli na obiektach w @books i tworzenie elementów w oparciu o atrybu- ty każdego obiektu Book. Za pomocą wywołania Book.find w akcji rss z ograniczeniem do dwóch obiektów wyniko- we źródło RSS dla tego rozwiązania zwróci następujący kod: ?xml version= 1.0 encoding= UTF-8 ? rss version= 2.0 channel title Najnowsze książki wydawnictwa O Reilly /title link http://orsini.us:3000/xml/rss /link description Najnowsze książki wydawnictwa O Reilly /description language pl /language ttl 40 /ttl pubDate Sun, 30 Apr 2006 17:34:20 PDT /pubDate item title Rewolucja w dolinie /title link http://orsini.us:3000/posts/show/20 /link description Uznawany za współtwórcę komputera Macintosh, Andy Herzfeld przedstawia informacje z pierwszej ręki na temat zdarzeń i postaci, które doprowadziły do wydania tego rewolucyjnego urządzenia. /description guid http://orsini.us:3O00/posts/show/20 /guid /item item title Excel 200. Indywidualne szkolenie /title link http://orsini.us:3000/posts/show/17 /link description Dzięki temu wyczerpującemu podręcznikowi podstaw pracy z arkuszem kalkulacyjnym poznamy edycję i formatowanie, pracę z formułami, diagramy i wykresy, makra, metody integracji programu Excel z innymi programami oraz szereg tematów zaawansowanych. /description guid http://orsini.us:3000/posts/show/17 /guid /item /channel /rss Stosunkowo rozwlekłe wywołanie Time.now.strftime jest tu konieczne, aby utworzyć po- prawny format daty zgodny z RFC-822, czego wymaga specyfikacja RSS 2.0 (metoda Ruby Time.now pomija znak przecinka). Zobacz również Walidator W3C, http://validator.w3.org/feed, Specyfikacja RSS 2.0, http://blogs.law.harvard.edu/tech/rss. (cid:129) (cid:129) 5.8. Generowanie źródeł RSS z danych Active Record | 183 5.9. Ponowne wykorzystanie elementów za pomocą podszablonów Problem Chcemy wyeliminować powtarzanie się kodu w naszych szablonach przez rozbicie części sza- blonów w mniejsze podszablony. Chcielibyśmy wykorzystywać te podszablony wielokrotnie w tym samym szablonie, a nawet w różnych szablonach. Aby jeszcze bardziej zwiększyć ich przydatność, takie szablony wielokrotnego użytku powinny akceptować zmienne lokalne prze- syłane do nich jako parametry. Rozwiązanie Wykorzystamy ponownie kod przez utworzenie i wygenerowanie podszablonów (ang. par- tials), opcjonalnie przesyłając zmienne z szablonu macierzystego w celu ich użycia w podsza- blonach. Aby to zademonstrować, skonfigurujemy kontroler Properties z akcją list, która wypełni właściwościami zmienną egzemplarza. app/controllers/properties_controller.rb: class PropertiesController ApplicationController def list @properties = Property.find(:all, :order = date_listed , :limit = 3) end end Podszablon przypomina dowolny inny szablon, jednak rozszerzenie jego pliku rozpoczyna się znakiem podkreślenia. Utwórzmy podszablon o nazwie _property.rhtml i przeprowadźmy w nim iterację zawartości tablicy @properties i wyświetlmy jej zawartość. Za pomocą meto- dy cycle nadamy kolejnym wierszom listy nieruchomości na przemian kolor biały oraz kolor przypisany do wartości zmiennej lokalnej bgcolor. app/views/properties/_property.rhtml: div style= background: = cyde(bgcolor, #fff ) ; padding: 4px; strong Adres: /strong = property.address br / strong Cena: /strong = number_to_currency(property.price) br / strong Opis: /strong = truncate(property.description, 60) /div Generujemy podszablon _property.rhtml z widoku list.rhtml za pomocą wywołania metody render, przesyłając nazwę podszablonu (nazwę jego pliku, bez znaku podkreślenia i rozszerze- nia) do opcji :partial. Dodatkowo przesyłamy też do szablonu bgcolor jako zmienną lokal- ną, przypisując ją do wartości :bgcolor w tablicy asocjacyjnej przesyłanej do opcji :locals. 184 | Rozdział 5. Action View app/views/properties/list.rhtml: h3 Spis nieruchomości: /h3 = render(:partial = property , :locals = {:bgcolor = #ccc }, :collection = @properties ) Omówienie Wywołanie akcji list kontrolera Properties z tego rozwiązania wyświetli informacje na temat każdej nieruchomości, z zastosowaniem naprzemiennych kolorów tła. Domyślnie pod- szablony mają dostęp do zmiennej egzemplarza o tej samie nazwie, co podszablon, podobnie jak szablon list.rhtml ma dostęp do zmiennej egzemplarza @properties. Jeśli takie zachowa- nie domyślnie jest niepożądane, możemy przesłać dowolną zmienną lokalną, włączając ją do tablicy asocjacyjnej przesyłanej do opcji :locals metody render. Taki podszablon możemy wywołać z dowolnego innego szablonu w naszej aplikacji, prze- syłając ścieżkę bezwzględną do opcji :partial metody render. W rzeczywistości, jeśli nasz podszablon zawiera jakiekolwiek ukośniki, Rails będzie szukał tego podszablonu w odniesie- niu do katalogu app/view naszej aplikacji. Rozwiązanie przesyła :partial = property do metody render, nakazując jej odszukanie pliku o nazwie _property.rhtml w katalogu app/views/properties (tym samym, w którym znaj- duje się list.rhtml). Jeśli property poprzedzimy ukośnikiem, np. :partial = /property , wówczas metoda render będzie szukać tego podszablonu w katalogu app/views. Takie zacho- wanie jest przydatne, jeśli planujemy współdzielić podszablony z szablonami widoków róż- nych kontrolerów. Powszechnie przyjętą konwencją jest utworzenie w katalogu app/views pod- katalogu przeznaczonego na współdzielone podszablony, a następnie poprzedzanie ścieżki do podszablonu ukośnikiem i nazwą takiego wspólnego katalogu (np. :partial = /shared/ property ). Tworząc podszablon do obsługi wyświetlania pojedynczego obiektu, możemy go wciąż po- nownie wykorzystywać. Ten sam podszablon, który wywoływaliśmy wcześniej z szablonu list.rhtml, możemy teraz użyć z szablonu show.rhtml, który (zgodnie z konwencją) generuje pojedynczy model. Oto, jak wygląda szablon show: app/views/properties/show.rhtml: h3 Spis nieruchomości: /h3 = render :partial = property , :locals = {:property = @property} Dodajemy do kontrolera metodę show: app/controllers/properties_controller.rb: class PropertiesController ApplicationController def list @properties = Property.find(:all, :order = date_listed , :limit = 3) end 5.9. Ponowne wykorzystanie elementów za pomocą podszablonów | 185 def show @property = Property.find(params[:id]) end end Na rysunku 5.6 przedstawiono wynik każdej wersji wyświetlającej wiele obiektów Property przy użyciu podszablonów. Rysunek 5.6. Widok przedstawiający spis nieruchomości oraz pojedynczą nieruchomość; obie strony zostały wygenerowane przy użyciu tego samego podszablonu Zobacz również Receptura 5.5, „Wyodrębnianie wspólnego kodu prezentacyjnego za pomocą makiet”. (cid:129) 186 | Rozdział 5. Action View 5.10. Przetwarzanie pól wejściowych tworzonych dynamicznie Problem Chcemy zbudować i przetwarzać formularz składający się z dynamicznie tworzonych pól wejściowych. Załóżmy, że mamy tabelę użytkowników, z których każdy może zostać powią- zany z jedną rolą lub większą liczbą ról. Zarówno użytkownicy, jak i role pochodzą z bazy danych; nowych użytkowników i role można będzie dodać w każdej chwili. Chcemy umoż- liwić zarządzanie relacjami zachodzącymi między użytkownikami a rolami. Rozwiązanie Czasami najłatwiej administrować takimi relacjami za pomocą tabel zawierających pola wy- boru, po jednym na każdą możliwą relację między dwoma modelami. Zaczniemy od utworzenia tabel zawierających użytkowników i role oraz tabeli uprawnień do przechowywania powiązań: db/schema.rb: ActiveRecord::Schema.define(:version = 0) do create_table roles , :force = true do |t| t.column name , :string, :limit = 80 end create_table users , :force = true do |t| t.column login , :string, :limit = 80 end create_table permissions , :id = false, :force = true do |t| t.column role_id , :integer, :default = 0, :null = false t.column user_id , [integer, :default = 0, :null = false end end W celu zwiększenia elastyczności w manipulacji danymi w tabeli łączącej tworzymy relację wiele-do-wielu, korzystając z opcji :has_many :through: class Role ActiveRecord::Base has_many :permissions, :dependent = true has_many :users, :through = :permissions end class User ActiveRecord::Base has_many :permissions, dependent = true has_many :roles, :through = :permissions end class Permission ActiveRecord::Base belongs_to :role belongs_to :user end 5.10. Przetwarzanie pól wejściowych tworzonych dynamicznie | 187 Tworzymy teraz kontroler UserController z akcjami służącymi do wyświetlania i aktualizo- wania wszystkich możliwych powiązań między użytkownikami a rolami: app/controllers/user_controller.rb: class UserController ApplicationController def list_perms @users = User.find(:all, :order = login ) @roles = Role.find(:all, :order = name ) end def update_perms Permission.transaction do Permission.delete_all for user in User.find(:all) for role in Role.find(:all) if params[:perm][ #{user.id}-#{role.id} ] == on Permission.create(:user_id = user.id, :role_id = role.id) end end end end flash[:notice] = Zaktualizowano uprawnienia. redirect_to :action = list_perms end end Następnie tworzymy widok dla akcji list_perms, która będzie budować formularz zawiera- jący tabelę z polami wyboru na przecięciach użytkowników i ról: app/views/user/list_perms.rhtml: h2 Administracja uprawnieniami /h2 if flash[:notice] p style= color: red; = flash[:notice] /p end form_tag :action = update_perms do table style= background: #ccc; tr th nbsp; /th for user in @users th = user.login /th end /tr for role in @roles tr style= background: = cycle( #ffc , white ) ; td align= right strong = role.name /strong /td for user in @users td align= center = get_perm(user.id, role.id) /td end end /table br / = submit_tag Zapisz zmiany end 188 | Rozdział 5. Action View Metoda pomocnicza get_perm użyta w widoku list_perms tworzy kod HTML dla każdego pola wyboru w formularzu. Definiujemy ją w pliku user_helper.rb: app/helpers/user_helper.rb: module UserHelper def get_perm(role_id, user_id) name = perm[#{user_id}-#{role_id}] perm = Permission.find_by_role_id_and_user_id(role_id, user_id) color = #f66 unless perm.nil? color = #9f9 checked = checked= checked end return span style= background: #{color}; input name= #{name} type= checkbox #{checked} /span end end Omówienie Rozwiązanie rozpoczyna się od utworzenia powiązań typu wiele-do-wielu między tabelami użytkowników i ról za pomocą metody Active Record has_many :through. Umożliwia to manipulowanie danymi w tabeli uprawnień, a także skorzystanie z metody transaction kla- sy Permission. Po skonfigurowaniu relacji między tabelami kontroler User przechowuje wszystkich użytkow- ników i obiekty ról w zmiennych egzemplarza, które są dostępne dla widoku. Widok list_ perms rozpoczyna od pętli, która przeprowadza iterację użytkowników, wyświetlając ich jako nagłówki kolumn. Następnie tworzona jest tabela uprawnień użytkowników przez wykona- nie pętli na rolach, które stają się wierszami tabeli, z drugą pętlą przeprowadzającą iteracje użytkowników (po jednym na każdą kolumnę). Formularz składa się z tworzonych dynamicznie pól wyboru umieszczonych na przecięciach każdego użytkownika i roli. Każde pole wyboru jest identyfikowane przez łańcuch stanowią- cy połączenie łańcuchów user.id i role.id (perm[#{user_id}-#{role_id}]). Po zatwierdze- niu formularza params[:perm] jest tablicą asocjacyjną zawierającą wszystkie pary user.id/ role.id. Zawartość tej tablicy wygląda następująco: irb(# UserController:0x405776a0 ):003:0 params[:perm] = { 2-2 = on , 2-3 = on , 1-4 = on , 2-4 = on , 1-5 = on , 4-4 = on , 5-3 = on , 4-5 = on , 5-4 = on , 1-1 = on } Akcja update_perms kontrolera User rozpoczyna działanie od usunięcia wszystkich istnieją- cych obiektów Permission. Ponieważ podczas pozostałego działania tej akcji mogłoby się wydarzyć coś nieprzewidzianego, całość kodu, który dokonuje zmian w bazie danych, objęta zostaje transakcją Active Record. Transakcja taka zapewnia, że usunięcie powiązania użyt- kownik-rola zostanie cofnięte, gdyby w dalszym działaniu metody coś się nie powiodło. W celu przetworzenia wartości pól wyboru update_perms odtwarza zagnieżdżoną strukturę pętli, która tworzy elementy pola wyboru w widoku. Po zrekonstruowaniu nazwy każdego pola zostaje ono użyte do uzyskania dostępu do wartości w tablicy asocjacyjnej, które są prze- chowywane z wykorzystaniem tej nazwy jako klucza. Jeżeli wartość wynosi on, akcja tworzy obiekt Permission, który przypisuje rolę do określonego użytkownika. 5.10. Przetwarzanie pól wejściowych tworzonych dynamicznie | 189 Widok stosuje kolory w celu wskazania uprawnień, jakie istniały, zanim użytkownik je zmie- nił: kolor zielony oznacza powiązanie, a czerwony — jego brak. Na rysunku 5.7 przedstawiono matrycę pól wejściowych utworzonych w tym rozwiązaniu. Rysunek 5.7. Formularz zawierający wygenerowaną dynamicznie matrycę pól wyboru Zobacz również Receptura 5.12, „Tworzenie formularzy WWW z wykorzystaniem metod pomocniczych”. (cid:129) 5.11. Dostosowywanie zachowań standardowych metod pomocniczych Problem Udostępnił Diego Scataglini Znaleźliśmy metodę pomocniczą, która robi prawie dokładnie to, czego potrzebujemy, ale chce- my zmienić jej zachowanie domyślne. Chcielibyśmy np., aby metoda pomocnicza content_ helper obsługiwała parametr blokowy. 190 | Rozdział 5. Action View Rozwiązanie W przypadku tej receptury wykorzystamy istniejącą aplikację Rails lub utworzymy nową w celu swobodnego eksperymentowania z nią. Nadpisujemy definicję metody pomocniczej content_tag przez dodanie poniższego kodu do pliku app/helpers/application_helper.rb: def content_tag(name, content, options = nil, block) content = #{content}#{yield if block_given?} super end Normalnie użylibyśmy metody content_tag następująco: content_tag( h1 , @published_bookmark.title + : + content_tag( span , opublikowana przez przez + link_to(@user_login, user_url(:login = @published_bookmark.owner.login), :style = font-weight: bold; ), :style = font-size: .8em; ), :style = padding-bottom: 2ex; ) Poprzednia struktura jest nieco zbyt skomplikowana. Dzięki zmodyfikowaniu content_tag możemy użyć
Pobierz darmowy fragment (pdf)

Gdzie kupić całą publikację:

Rails. Receptury
Autor:

Opinie na temat publikacji:


Inne popularne pozycje z tej kategorii:


Czytaj również:


Prowadzisz stronę lub blog? Wstaw link do fragmentu tej książki i współpracuj z Cyfroteką: