//DEVGURU

Author's entries:

Fragment caching with Memcache and Rails 2.1

Saturday, January 10th, 2009

I’ve only recently had a possibility to try the new Rails 2.1 integrated caching. What I first learned was that there hardly is any documentation about it.

So it took me a while to find out that caching HTML fragments with time-based expiration (with Memcache) is as easy as adding:

config.cache_store = :mem_cache_store, { :namespace => 'myapp_production' }

to your config/environments/production.rb to specify Memcache as the caching mechanism. You can also use memory, or filesystem, but let’s be serious here. Memcache is the way to go. What’smore, time-based expiration doesn’t work for the other ones.

Now you can use something like this in your view:

The hardest thing to google for was the :expires_in option. Remember it only works with memcache.

By the way, it’s a good idea to use Memcache also for session storage. To do so, add the following line to config/environments/production.rb.

config.action_controller.session_store = :mem_cache_store

For more information on the basics check out the blog post by TheWebFellas.

Rails – ampersandy w parametrach

Tuesday, November 4th, 2008

Na początku zaznaczę, że nie mam pojęcia kto jest winien poniższego zachowania (i, po prawdzie, nie interesuje mnie to zupełnie), ale jeśli można spokojnie problem rozwiązać na poziomie Railsów, to chyba tak jest najlepiej.

Otóż, gdy przekazujemy w URLu jakieś parametry (co mnie osobiście razi i staram się tego w miarę możliwości unikać), są one rodzielone znakiem ampersandu – &. Standardy mówią, że znak ten powinien być odpowiednio zakodowany jako & i tak jest w istocie, jeśli korzysta się z railsowych helperów do restful routes. Problem pojawia się, jak zwykle, gdy zaczniemy te standardy testować w różnych przeglądarkach. O ile się nie mylę (a mylić się mogę, bo nie sprawdziłem tego dobrze), przeglądarka powinna sama, po kliknięciu takiego linku, przekodować & z powrotem na &. Jednakże, moja ulubiona (Safari) tego nie robi. Efektem tego otrzymujemy hash z parametrami postaci:

Osobiście wolałbym się odwoływać do params[:name], a nie params["amp;name"], więc zacząłem szukać rozwiązania. Jest ono proste i nieskomplikowane - Rails not handling links with & correctly. Jeżeli ktoś lubi ręcznie patchować Railsy…

Dla tych co, podobnie jak ja, odczuwają “wewnętrzne fuj” przy takich czynnościach proponuję w zamian dodać (najlepiej gdzieś w lib) prosty monkey patch:

Paginacja po polsku, czyli numerowanie stron

Wednesday, October 29th, 2008

Prawie każdy projekt Railsowy, w którym wyświetla się jakiekolwiek dane z podziałem na strony korzysta z will_paginate, czy to w formie plugina, czy gema. Nie ma się co oszukiwać, jest to swego rodzaju standard, tak jak kiedyś attachment_fu (”kiedyś”, czyli do czasu pojawienia się Paperclipa). Zresztą, nie jest to dziwne, gdyż korzystanie z niego jest bardzo wygodne. Drobny problem pojawia się jedynie gdy chcemy dostosować will_paginate do polskich realiów.

Generowany przez will_paginate kod HTML domyślnie wygląda następująco:

My jednak znajdujemy się w kraju Piastów i rażą nas angielskie terminy “next” i “previous”. Jest na to proste rozwiązanie, wystarczy do metody will_paginate dodać odpowiednie parametry:

I mamy prawdziwie słowiańskie podpisy.

Jak ktoś chce pójść krok dalej i samemu zdefiniować jak powinna wyglądać numeracja stron, to polecam dobre wprowadzenie na blogu thewebfellas.

Fixing fixtures

Thursday, October 9th, 2008

Według American Heritage Dictionary słowo fixture oznacza:

fix·ture (fĭks’chər) n.

  1. Something securely fixed in place.
  2. Something attached as a permanent appendage, apparatus, or appliance: plumbing fixtures.
  3. Law A chattel bound to realty.
  4. One that is invariably present in and long associated with a place: a journalist who became a Washington fixture.
  1. The act or process of fixing.
  2. The condition of being fixed.
Otóż, nic bardziej mylnego. Railsowe fixtures możemy (i niektórzy w netguru z tej możliwości zawzięcie korzystają) z łatwością zamienić na coś innego. Chłopaki z thoughtbot bowiem wypuścili już jakiś czas temu gem factory_girl, który można bardzo łatwo zaprząc do zapełniania aplikacji danymi testowymi.
W tym miejscu należy się chyba odrobina wyjaśnienia do czego ja używam fixtures i dlaczego tradycyjna metoda mi nie odpowiada:
  1. Populacja bazy danych celem przeprowadzenia testów.
  2. Populacja bazy danych celem wygodniejszego ręcznego testowania aplikacji.
W pierwszym przypadku wolę przed konkretnymi testami tworzyć samemu potrzebne modele, żeby później zaglądając do pliku z testami mieć jasność na jakich danych operuję. Konieczność utrzymywania dużej bazy różnorodnych fixtures, żeby pasowały do wszystkich testów, które sobie wymyślę, jest męcząca.
W drugim przypadku tradycyjne fixtures odpadają ze względu na paskudny sposób definiowania relacji miedzy obiektami. Podawanie id z ręki dla mnie to czynność, którą można było wykonywać w XX wieku, a nie teraz. Foxy fixtures natomias generują tak kosmiczne id, że Sphinx sobie kiepsko radzi z indeksowaniem, mikroskopijnej przecież zwykle, bazy.
Po tej krótkiej dygresji na temat tego co mi się nie podoba, czas przejść do tego co mi się podoba, czyli wspomnianego wcześniej factory_girl. Opisywać instalacji ani dokumentacji nie bedę, bo każdy sobie sam po angielsku przeczyta, tylko napiszę co mi się w tym podoba.
Otóż mam możliwość prostego generowania obiektów, nawet tych bardziej skomplikowanych. Przykładowo mamy w aplikacji użytkowników, których logowanie jest obsługiwane przez restful_authentication. Czyli od samego początku mamy już ładne kilka pól w bazie do zdefiniowania przy tworzeniu takowego. Dzięki factory_girl (i dalej opisanej definicji modelu) możemy stworzyć go za pomocą prostego
Factory :user
Jeśli jednak zależy nam na użytkowniku, który ma konkretny login i nie jest jeszcze aktywowany, to możemy nadpisać domyślne ustawienia:
Factory :user, :login => ‘gracjan’, :activated_at => nil
Aby powyższe zadziałało wystarczy zdefiniować gdzieś (np. w lib) obiekty, które będziemy generować. Przykładową definicja (ze względu na czytelność) można obejrzeć na pastie.org.
Dodam jeszcze, że generowanie obiektów w ten sposób uruchamia wszelkie before- i after_create oraz walidacje i już mamy pełne wyjaśnienie dlaczego zapomniałem tradycyjne fixtures i poznałem starych Rolling Stonesów.

Sphinx, a sprawa polska

Friday, July 18th, 2008

Jak pierwszy raz dodawałem wyszukiwarkę do aplikacji Railsowej, to wybór był prosty, bo właściwie nie było żadnego – acts_as_ferret. W pierwszej chwili byłem bardzo mile zaskoczony, bowiem korzysta się z tego niezwykle prosto, można indeksować nie tylko pola znajdujące się w bazie, ale również wyniki wywołania metod modelu, indeksowanie odbywa się na żywo. Super sprawa.

Jakiś czas później jednak zaczęły się schody – indeksowanie na żywo po pewnym czasie generowało błędne wyniki, poważnie zwalniało operacje na większej ilości danych (konieczność przeindeksowania po każdej zmianie), a na koniec na serwerze produkcyjnym ferret w pewnym momencie całkowicie odmówił współpracy, sypiąc jakimiś błędami, o których developerzy wiedzą, ale nie mogą ich powtórzyć, a co za tym idzie, naprawić.

Szczęśliwie wtedy już sytuacja na polu wyszukiwania w Railsach nie była już taka jednoznaczna. Poza Ferretem był również javowski Solr (którego można używać za pomocą acts_as_solr) i rosyjski Sphinx. Zdecydowałem się na tego ostatniego i okazało się to potem świetną decyzją. Ma niesamowite tempo indeksowania – zbiory, których indeksowanie przez Ferreta nie zmieściłoby się w ośmiogodzinnym dniu pracy były trawione w kilka minut. Oczywiście, są też pewne minusy – brak indeksowania na żywo (podobno do obejścia przez zastosowanie delta indeksów, ja nie miałem jak dotąd takiej potrzeby), wydłużony czas indeksowania jeśli chcemy później przeszukiwać z użyciem infiksów i prefiksów (lecz nadal o wiele szybszy niż w przypadku Ferreta) i brak możliwości indeksowania treści, które nie znajdują się bezpośrednio w bazie.

Sphinxa łatwo zintegrujemy z aplikacją korzystając z jednego z dwóch sprawdzonych przeze mnie pluginów – Thinking Sphinx i Ultrasphinx. Ten pierwszy jest prostszy w konfiguracji, wygodniejszy w użyciu, ale Ultrasphinx posiada większe możliwości i jest tym pluginem, którego nalezy użyć jeśli posiada się nietypowo umieszczone dane w bazie (jako, że pozwala na pisanie własnych zapytań SQL do wyciągania danych).

Przy podłączaniu Sphinxa do Railsowej aplikacji jest jedna rzecz, która sprawiała problemy – reprezentacja polskich znaków. Baza jest w UTF-8, ale znając lenistwo niektórych przy wpisywaniu polskich znaków chcielibyśmy, aby frazy wyszukiwania ‘Zażółć gęślą jaźń’ i ‘zazOlC gesLA jazN’ dawały te same wyniki. Należy wtedy dokonać drobnej manipulacji zmienną charset_table w pliku konfiguracyjnym Sphinxa. W moim przypadku przyjęła ona taką postać.

Jest to zapożyczenie wzbogacone przeze mnie o niektóre brakujące polskie znaki diakrytyczne. Dane z bazy są sprowadzane do zbioru małych liter alfabetu łacińskiego i takoż indeksowane. Jeśli komuś brakuje jakiegoś znaku wśród tych reguł, to warto skorzystać z wyszukiwarki znaków i znaleziony tam kod dodać do pliku konfiguracyjnego.