//DEVGURU

Archives: December, 2008

FirePHP – Firebug Extension for AJAX Development

Saturday, December 27th, 2008

Nie raz pewnie spotkaliście się z problemem debugowania skryptów PHP wywoływanych przez AJAX. O ile w jednorazowych przypadkach wystarczy FireBug w Firefoxie (linia czasowa sieci w Safari) w połączeniu z dumpem interesujących nas zmiennych, to w przypadku zapytań zwracających kod JSON lub XML pojawia się problem. Gdy dopiszemy coś do zapytania, format zwracanej treści przestanie być już poprawny i nasz skrypt JS może nie zadziałać poprawnie.

Rozwiązaniem tego problemu jest właśnie FirePHP. Jest to z jednej strony dodatek do Firefoxa, który rozszerza funkcjonalność znanego wszystkim FireBuga, a z drugiej strony biblioteka PHP umożliwiająca przesyłanie informacji do konsoli FireBuga. Jak to się dzieje? PHP dodaje nagłówek X-FirePHP-Data w którym znajduje się obiekt JSON z informacjami dla konsoli. Dodatek do przeglądarki informacje te przechwytuje i wyświetla.

Szczegółowe informacje o zastosowaniach FirePHP wraz z przykładami znajdują się na stronie. Warto jednak najpierw zajrzeć na stronę Wiki, ponieważ tam znajdują się informacje o dodatkach implementujących wykorzystanie FirePHP w takich frameworkach jak Zend, CodeIgniter, Kohana czy CakePHP. Niektóre z nich – np. Zend pozwala na przesyłanie profilera bazy danych do FirePHP.

Więcej o zastosowaniu FirePHP można było przeczytać również w listopadowym numerze php|architect.

Netguru @ CR & IT Conference, Częstochowa

Monday, December 15th, 2008

W miniony weekend poprowadziliśmy 4 prezentacje na konferencji CR & IT w Częstochowie:

Materiały są podlinkowane.

Techaula dla technofanów :-)

Wednesday, December 10th, 2008

Jak donosi Grzegorz Wolański, 16 grudnia o godzinie 18:00 w Warszawie odbędzie się czwarte spotkanie programistów z cyklu TechAula poświęcone systemom kontroli wersji (VCS).

Zygmunt Krynicki (Samsung Electronis Polska) zaprezentuje Baazar, Alexey Shabalovskiy (Embiq) opowie o Mercurialu, a Paweł Kołodziej będzie przekonywał do darcsa.

Szczegóły na www.aulapolska.pl.

Rails, Ajax i jQuery

Tuesday, December 9th, 2008

Poniżej przedstawiam swoje podejście do wprowadzania ajaxowych funkcjonalności do aplikacji napisanych w Ruby on Rails. Jest to zbitka rozwiązań znalezionych na różnych blogach, forach oraz trochę moich przemyśleń. Do obsługi Javascript używam biblioteki jQuery, nie korzystam z jRails ani żadnych helperów do JS/Ajax dostępnych z Rails. Dzięki temu cały kod javascriptowy/htmlowy zaprezentowany poniżej może być bez trudu użyty w aplikacjach napisanych w innych językach/frameworkach. Zacznijmy.

Ruby on Rails a REST

Requesty ajaxowe różnią się trochę od zwykłych requestów, które dochodzą do serwera gdy użytkownik wpisze URL w przeglądarce. A przynajmniej powinny się różnić, żebyśmy po stronie serwera wiedzieli jaką odpowiedź (widok) zwrócić, nie ma bowiem sensu renderować całego layoutu np. dla requestu ajaxowego oceniającego zdjęcie w naszym serwisie. Tym aspektem odróżniającym różne typy requestów jest w tym przypadku nagłówek zawierający oczekiwany format odpowiedzi od serwera.

Dzięki implementacji REST w Railsach, sposób w jaki obsługujemy akcje jest zawsze taki sam niezależnie od typu requestu, jedyna zmiana dotyczy zwracanego przez nas widoku. Decydujemy o tym w kontrolerze:

To, który blok zostanie wywołany i w efekcie tego jaki widok zwrócony, zależy od route’ów zdefiniowanych w routes.rb oraz od oczekiwanego przez klienta formatu danych. W większości chcielibyśmy, żeby wszelkie ajaxowe requesty oczekiwały formatu XML (w odróżnieniu od HTML dla normalnych requestów), dlatego musimy zadbać o to, by przeglądarka odpowiednio ustawiała nagłówek Accept na ‘text/xml’ przy wywołaniach ajaxowych. W jQuery możemy ustawić to od razu dla wszystkich requestów z góry:

Różnice między przeglądarkami

Ręczne ustawienie nagłówka Accept niestety potrafi dawać różne efekty w różnych przeglądarkach. Wartością domyślnie ustawianą w przeglądarkach dla tego nagłówka jest text/html. Przy wywołaniu powyższego kodu Firefox zmieni wartość na ‘text/xml’, podczas gdy niektóre wersje IE i Safari ustawią ‘text/html; text/xml’ oczekując w ten sposób odpowiedzi od serwera w jednym z tych dwóch formatów.

Jest to dość istotna różnica, ponieważ Railsy decydując o tym, który format odpowiedzi wybrać, biorą pod uwagę pierwszy format napotkany w tablicy request.accept, którym w przypadku IE i Safari będzie text/html. Takie zachowanie zaobserwowałem chociażby w wersji 2.1.0 Railsów.

Poniższy kod naprawia opisane zachowanie przenosząc format xml na początek tablicy (jeśli się tam w ogóle znajduje), dzięki czemu będzie on znaleziony jako pierwszy.

Ajaxowe linki

Poniższy kod Javascript pozwala szybko zamienić istniejące już linki na działające ajaxowo. Proponuję go wrzucić do pliku appliacation.js.

 

Teraz wystarczy dodać do istniejących linków klasę (CSS’ową) get, post, put lub delete w zależności od pożądanej metody wywołania linku, by zmienić je w linki ajaxowe. Polecam do tego plugin LiveQuery, który to zachowanie automatycznie podepnie także do każdego nowego linku opatrzonego którąś z tych klas, który pojawi się na stronie (np. w efekcie działania jakiegoś wywołania ajaxowego). Dodatkowo do naszych linków możemy dodać opcjonalny atrybut ajaxtaget i ustawić jego wartość na selektor CSS’owy wskazujący na element, do którego zostanie załadowany widok zwrócony przez serwer.

Ajaxowe formularze

Do wysyłki formularzy porzez ajax będziemy potrzebować kolejnego pluginu – jQuery Form.

Ajaxowe formularze będą identyfikowane poprzez CSS’ową klasę ‘ajax’.

Modyfikacja strony po wywołaniu ajaxowym

Standardowym sposobem wyświetlania efektów wywołania ajaxowego jest odbieranie, obróbka i umieszczenie tego, co ono zwróci w jakimś miejscu na stronie. Innym sposobem jest umieszczenie całego kodu modyfikującego stronę w odpowiedzi zwracanej przez ajaxowe wywołanie i tylko wykonywanie go przez przeglądarkę. Taką funkcjonalność daje nam kolejny plugin do jQuery – Taconite. Cytując autora pluginu: “Taconite pozwala wykonywać modyfikacji wielu elementów strony naraz, korzystając z odpowiedzi zrwóconej przez pojedyncze wywołanie ajaxowe. Taconite używa do tego XML’owego dokumentu zawierającego instrukcję jak modyfikować stronę”.

Przykładowy widok XML z instrukcjami dla Taconite wygląda tak:

Dzięki podejściu oferowanym przez Taconite możemy poprawić strukturę aplikacji. Weźmy dla przykładu wspomnianą wcześniej funkcjonalność głosowania. Do tej pory kod Javascriptowy, który dbał o wyświetlenie rezultatów oddania głosu (np. zwiększenie countera, usunięcie linku ‘głosuj’, wyświetlenie komunikatu ‘głos został oddany’, itp) musiał być umieszczany na każdej stronie, na której było możliwe oddanie głosu. Teraz jest on po prostu zwracany jako odpowiedź serwera na oddanie głosu, czyli znajduje się tam gdzie być powinien.

Kolejny przykład – wyświetlanie flash messages w odpowiedzi na wywołania ajaxowe. Załóżmy, że to jest fragment layoutu naszej strony, w którym wyświetlamy komunikaty flash[:notice]:

Niech to będzie layout taconite, w którym zagnieżdzamy widoki zwracane na wywołania ajaxowe:

Teraz komunikaty flash[:notice] będą wyświetlane w standardowym miejscu na stronie z efektem fade-in. W podobny sposób możemy aktualizować inne elementy strony, np. wszelakie countery.

A Ty jakich narzędzi używasz?

Jestem ciekaw jakich rozwiązań używacie do implementacji Ajaxa w Waszych aplikacjach. Preferujecie jakieś inne pluginy/biblioteki?

Przyspieszanie nowych Railsów: memoization

Tuesday, December 9th, 2008

Problem?

Termin memoization nie jest niczym nowym w programowaniu, prawie-rzetelne źródła podają rok 1968 jako pierwsze pojawienie się go.

Na czym polega memoizacja (że tak sobie pozwolę na spolszczenie)? Proste: metoda zapamiętuje (można o tym pomyśleć jak o keszowaniu) swój wynik (w zależności od podanych argumentów) i wywołana kolejny raz – zwraca zapamiętaną i zamrożoną wartość.

Implementacja w Railsach

Memoization było często stosowaną praktyką – pisane “z ręki”, ale jako metoda ActiveSupport weszło do core railsów kilka m-cy temu, dzięki czemu wyszło wraz z wersją 2.2. Spróbujmy!

W ten sposób metoda wywołana kolejny raz nie będzie wykonywać skomplikowanych obliczeń, a jedynie zwróci swoją zmemoizowaną wartość. Co więcej, metoda może przyjmować argumenty – i zapamiętuje swoją wartość w zależności od podanego argumentu!

Tak więc mamy bardzo miły sposób na nie-zarzynanie rubiego.

Kiedy nie stosować memoizacji?

W przypadku dynamiczności zwracanych wyników (kiedy metoda korzysta np. z Time.now). Wyniki są zamrożone dla danego requestu i jeśli chcemy, żeby podczas niego obliczała coś kilka razy – odpuścmy sobie memoizację (lub wykonajmy zmemoizowaną metodę z symbolem :reload jako ostatnim argumentem).