//DEVGURU

Category archives ‘Ajax’

Rails 2.2.2, Ajax and respond_to

Saturday, January 31st, 2009

As I wrote some time ago in the article about Rails, Ajax and jQuery, sometimes there are problems with Rails not interpreting correctly content type headers of ajax requests. It’s because not all web browsers send that header in the same way.

What I proposed was to sort the request.accepts array (array containing content type headers sent by browser) so that xml content type would be the first element. That would then trigger format.xml in our respond_to block.

However that approach does not work in Rails 2.2.2, because now the request.accepts array is frozen and it cannot be modified. I spent some time googling for the solution, but with no effect. So I dived into the API and Rails’ source code and came up with pretty nice and simple solution to the problem.

class ApplicationController < ActionController::Base
  before_filter :xhr_to_xml

  def xhr_to_xml
    request.format = :xml if request.xhr?
  end
end

This piece of code is an equivalent of the snippet I proposed in the article I referred to at the beginning. Now all ajax request will trigger format.xml in respond_to blocks.

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.

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?