//DEVGURU

Archives: October, 2008

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.

Ulepszanie Railsowego Paperclipa

Sunday, October 26th, 2008

Paperclip to obecnie jeden z najlepszych, o ile nie najlepszy plugin do Ruby on Rails automatyzujący proces uploadu plików na serwer. Potrafi m.in. od razu sam wygenerować miniaturki zapisywanych obrazków, obsługuje także zapis na serwerach S3 Amazona. Każdy, kto go używał na pewno docenia jego zalety i prostotę obsługi, ale myślę też, że wielu natknęło się na sytuacje gdy okazał się on jednak niewystarczający.

Przykładowo, miniaturki obrazków generowane są zawsze w ten sam standardowy sposób co daje zamierzony efekt w większości przypadków, ale gdy chcemy poddać nasz obrazek jakimś dodatkowym transformacjom podczas skalowania, okazuje się to niemożliwe.

Innym przykładem jest obsługa S3 Amazona. Paperclip potrafi tam zapisywać pliki bez żadnych problemów, wystarczy, że podamy nasz API key oraz nazwę bucketa, do którego trafiać mają pliki. Co jednak w sytuacji gdy później na jednej stronie chcemy wyświetlić na raz wiele zuploadowanych zdjęć siedzących w jednym buckecie? Zdjęcia będą się ładować wolno. A to dlatego, że większość przeglądarek ma domyślnie włączone ograniczenie pozwalające w jednej chwili pobierać tylko 2 pliki z jednego hosta, niezależnie od dostępności łącza. Zatem dobrze było by rozmieścić nasze zdjęcia na wielu hostach (bucketach), żeby zwiększyć prędkość pobierania.

Na szczęście dzięki przemyślanej budowie samego pluginu i możliwości łatwego rozszerzania klas i modułów z dowolnego miejsca w języku Ruby nic nie stoi na przeszkodzie, żeby powyższe funkcjonalności dodać samemu.

Postanowiliśmy więc nie czekać na developerów Paperclipa i stworzyliśmy pakiet własnych rozszerzeń – PaperclipExtended. Znajdziecie tam rozwiązania powyżej wymienionych problemów oraz paru mniejszych. Jeśli okaże się, że jeszcze czegoś nam brakuje, na pewno to dodamy.

P.S. Paperclip 3.0 ma zawierać możliwość dowolnego definiowania komend przekształcających obrazki (coś a’la commands w PaperclipExtended) oraz móc skalować pliki video. Ale to dopiero w planach developerów, zanim się tego doczekamy, musimy działać sami :)

SwfUpload a Flash 10

Tuesday, October 21st, 2008

Swfupload to bardzo zgrabne połączenie flasha z javascriptem, które w efekcie daje nam mechanizm uploadu plików na serwer, który możliwościami znacznie wykracza poza standardowy <input type=”file” …/>. Podstawowe zalety, to możliwość uploadu wielu plików naraz i pokazywanie paska postępu całego procesu.

Jednak nie wszystko zawsze działa tak jak należy. Część problemów z używaniem tej biblioteki wynika z różnic pomiędzy kolejnymi wersjami Flasha lub błędów w implementacji niektórych funkcjonalności po stronie Flasha właśnie. Część z tych problemów i metod ich rozwiązania opisałem kiedyś na blogu CodeTunes, ale teraz wyszła nowa wersja Flasha – 10.

Flash 10 podchodzi trochę bardziej restrykcyjnie do niektórych aspektów bezpieczeństwa od swoich poprzedników. Jedną z takich zmian jest zablokowanie wywołania okna dialogowego do wyboru plików spoza flasha, co bezpośrednio uderza w SwfUpload, który robił to z poziomu Javascript.

Na szczęście reakcja developerów SwfUpload’a była dość szybka i rozpoczęli prace nad wersją 2.2 biblioteki, która już radzi sobie z tym problemem. Warto jednak zauważyć, że wersja 2.2, pomimo kompatybilności z Flashem 10 we wspomianym aspekcie, znajduje się jeszcze w fazie alpha, więc może mieć wciąż jakieś niedociągnięcia. Polecam więc upgrade do stabilnej wersji jak się tylko ukaże.

Poniżej instrukcja jak przekonfigurować swoją aplikację do używania SwfUpload w wersji 2.2.

Najpierw ściągamy najnowszą wersję biblioteki z SVN

svn co http://swfupload.googlecode.com/svn/swfupload/trunk/core swfupload

Z tego co sciągniemy potrzebujemy tylko dwa pliki: swfupload/swfupload.js i swfupload/Flash/swufpload.swf. Są to nowe wersje plików, które już powinniśmy mieć w swojej aplikacji, więc podmieniamy stare na nowe.

W nowej wersji SwfUpload sam sobie generuje przycisk otwierający okienko z wyborem plików, my musimy tylko wskazać mu miejsce gdzie ma go umieścić.

<div id="swfuploadButtonPlaceHolder"></div>

Pozostaje nam jeszcze tylko zmiana w opcjach z poziomu Javascript:

swfu = new SWFUpload({
...
button_placeholder_id: "swfuploadButtonPlaceHolder",
button_image_url: "../images/swfupload/button.jpg",
button_width: "216",
button_height: "25"
...});

Ścieżka do “button_image_url” musi być relatywna do lokalizacji pliku swf, a sam obrazek, na który wskazuje powinien wyglądać mniej więcej tak:

Czyli jeden obrazek zawierający 3 stany przycisku (normalny, onmouseover, onclick). Zamiast obrazka możemy podać tekst:

swfu = new SWFUpload({
...
button_text: '<span class="theFont">Upload</span>',
button_text_style: ".theFont { font-size: 16; }"
...});

To wszystko. Działający przykład można obejrzeć tutaj.

Haml czyni cuda – czyli dlaczego koder HTML’a woli być koderem HAML’a

Monday, October 20th, 2008

Logo Hamla
Jakiś czas temu wewnątrz netguru rozgorzała krótka żarliwa dyskusja na temat “Czy warto uzywać HAML’a”. Małe wewnętrzne lobby, utworzone na potrzebę zdarzenia szybko przeforsowało taką decyzje i teraz programiści szczęśliwi mogą go używać do woli. OK.

Tylko po co to zamieszanie??

Gdy rozwiniemy skrót HAML (w moim przypadku zezując na drugi monitor gdzie otwarta jest strona projektu) dowiem się żę jest to (x)HTML Abstraction Markup Language – póki co nic fajnego. Starając jakoś to przybliżyc musimy powiedziec że jest to język używany do tworzenia szablonów, mogący zastąpić popularnego rhtml’a w frameworku RoR.

Pomijając moją nieudolną próbę definicji tego pojęcia HAML to w praktyce poprostu jeden wielki skrót HTML’a. Z założenia autorzy napisali go by ulżyc programistom framework’a RoR, ale plotka głosi istnieją wersje, które spokojnie zadziałają również w php i ASP .NET.

Jego podstawową zaletą jest fakt, że jest go najzwyczajniej w świecie mniej. To co tradycyjnie w rhtml’u wymagało napisania czegoś takiego:

<div class="jakas_klasa">
Treść która nas urzeka
</div>

w HAMLu sprowadza się do:

.jakas_klasa Treść która nas urzeka

I uwierzcie mi że potem jest tylko lepiej. Przeciętnie takie pisanie szablonu w HAML’u to ok 40% kodu, nie mówiąc już o tym jak przejrzyście robi się się w takich szablonach. Dla porównania przykład, który możemy znaleźć w tutorialu do HAML’a.
Rhtml:

<div id='content'>
  <div class='left column'>
    <h2>Welcome to our site!</h2>
    <p>
      <%= print_information %>
    </p>
  </div>
  <div class="right column">
    <%= render :partial => "sidebar" %>
  </div>
</div>

HAML:

#content
  .left.column
    %h2 Welcome to our site!
    %p= print_information
  .right.column= render :partial => "sidebar"

Widać tu od razu kilka sztuczek jakich używa się w HAML’u by definiować znaczniki. Tworząc nowy znacznik używamy składni %nazwa_znacznika, lub %nazwa_znacznika.klasa gdy chcemy stworzyć znacznik z atrybutem class albo %nazwa_znacznika#jakis_id gdy potrzebny nam atrybut id. Warto zauważyć dwa fakty – po pierwsze, html’owy div jest znacznikiem domyślnym w HAML’u i nie musimy go pisać, starczy zdefiniować tylko class lub id, po drugie HAML jest “white space sensitive” jak piszą autorzy – zmusza nas on do poprawnego wcinania kodu co w praktyce okazje się mieć zbawienne skutki. Wszystkich zainteresowanych większą ilością informacji zachęcam do dokładnego zapoznania się z tutorialem.

Część z Was pewnie jest w tym momencie wciąz zdegustowana początkiem mojej wypowiedzi gdzie wspomniałem, że “programiści szczęśliwi mogą go używać do woli”. Teoretycznie ze względu na fakt, że HAML oferuje nam zupełnie nową składnie do tworzenia szablonu, moglibyśmy powiedzieć że jest on nieużyteczny dla koderów HTML’a i CSS’a którz wcale nie muszą umieć programować. Ponieważ jest to faktycznie kluczowa kwestia postanowiłem zapytać o zdanie naszego firmowego kodera. Zapytany o HAML’a  Marcin powiedział:

HAML jest tak genialny, że po tym jak się go nauczyłem nie mogę zasnąć wieczorem zmartwiony myślą, iż nie jest mi dane używać go w każdym projekcie

(oczywiście wszycy którzy znają naszego kodera wiedzą jak bardzo sparafrazowana i ocenzurowana jest ta wypowiedź)

W praktyce faktycznie okazuje się, że autorzy nie kłamią pisząc:

Haml feels odd for the first 20 minutes, but then after that YOU WILL BE FASTER.

Oprócz genialnej w użyciu składni, najnowsza wersja 2.0  HAML’a oferuje nam nawet większą prędkość renderowana szablonów nić tradycyjny Rhtml, co wytąca jeden z najpoważniejszych argumentów jaki mieli sceptycy. Co więcej faktycznie po pierwszych 20 minutach prób z HAML’em jesteśmy już w stanie spokojnie z niego korzystać co skutkuje jak określa jeden z naszych teraz już “szczęśliwych” programistów:

Jest mniej tego plugawego htmla w kodzie!

(tym razem bez cenzury :P )

Devgurowy przegląd sieci

Monday, October 20th, 2008

Rozpoczynamy cykl krótkich postów z linkami do ciekawych zasobów, na które natrafiamy podczas pracy nad naszymi projektami. Oto pierwsza partia linków:

Znalazłeś ciekawy link? Dodaj go do flakera z tagiem #devguru. Przejrzymy i być może w przyszłym tygodniu umieścimy w przeglądzie.

Eksport do CSV w Ruby on Rails

Monday, October 13th, 2008

Wtyczek służacych do eksportu do CSV jest sporo, do tego w Rubym mamy nawet klasę CSV – co jednak, jeśli chcemy skorzystać z najprostszego sposobu eksportu do CSV?

Skorzystamy z Ruport.

Ruport, czyli Ruby Reports, w bardzo “czysty” sposób pozwala nam wyekportować dane do formatów takich jak CSV, PDF, HTML czy ładnie sformatowanego tekstu. W połączeniu z wtyczką acts_as_reportable eksport do CSV to banalna sprawa.

Instalacja

w config/environment.rb dodajemy linijki:

config.gem "ruport"
config.gem "acts_as_reportable"

a następnie za pomocą rake gems:install dodajemy je do naszej maszyny jeśli ich jeszcze nie mamy (uwaga – możliwe, że będziemy musieli zainstalować jeszcze gema fastercsv w odpowiedniej wersji – możemy dokonać tego za pomocą polecenia sudo gem install fastercsv -v 1.2.3).

Użycie

Następnie w odpowiednim modelu (przykładowo – User) dodajemy linię:

acts_as_reportable :only => [:name, :email, :company, :url]

Oczywiście argument :only nie jest wymagany, lecz jeśli nie chcemy zdradzać wszystkim haseł (nawet zakodowanych) czy ID – warto z niego skorzystać. Mamy też dostęp do analogicznie działającego :except czy kilku innych – warto przejrzeć rdocsy wtyczki.

Teraz stworzymy metodę w kontrolerze:

def download_csv
  filename = "lista uzytkownikow"
  response.headers['Content-Type' = 'text/csv'
  response.headers['Content-Disposition'] = 'attachment; filename="' + filename + '.csv"'
  render :text => User.report_table(:all).as(:csv)
end

I w ten sposób wywołując tę akcję dostajemy “ściągalny” plik z wybranymi danymi użytkowników. Banał, prawda?

Oczywiście zastosowań jest więcej – możemy ograniczyć użytkowników (za pomocą conditions czy też named scopes), zapisywać pdf na serwerze czy też zrobić co tylko chcemy – ważne, że wszystko jest proste i czyste.

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.

Hoptoad wysyła Exception Notifiera do /dev/null

Tuesday, October 7th, 2008

State-of-the-art-yści z thoughtbot zaprezentowali jakiś czas temu narzędzie do obsługi wyjątków w railsowych aplikacjach – Hoptoad. Po początkowym okresie fascynacji pt. “mój inbox jest czysty!” możemy powiedzieć kilka słów o projekcie.

Jedną z niezaprzeczalnych przewag Ruby’ego nad php jest obiektowość języka (tak, wiem, że php też jest obiektowy… trochę). Każdy błąd aplikacji możemy postrzegać jako wyjątek. Dzięki temu dostajemy dobry sposób na informowanie siebie samych o błędach w aplikacjach – ten feature jest szczególnie przydatny przy aplikacjach pracujących w produkcyjnym środowisku. W erze pre-hoptoadowej korzystaliśmy z Railsowego pluginu – Exception Notifiera. Działanie było proste: informacja o każdym wyjątku (razem z informacją o środowisku, użytkowniku, trace’m aplikacji itp.) była wysyłana mailem do zdefiniowanych adresów mailowych. Wady? Wyobraźmy sobie, że o godzinie 13 idziemy zjeść obiad. W tym czasie aplikacja nam się sypie, 300 użytkowników widzi stronę informującą o błędzie a my dostajemy 300 maili. Inny przykład? Wysyłamy maile korzystając z gmaila, skończył nam się dzienny limit wiadomości. Zgadnijcie – jak działa wtedy exception notifier?

“Koledzy” z thoughtbot postanowili załatwić tę sprawę raz na zawsze: informacja o wyjątku jest wysyłana za pomocą modułu Net::HTTP do API Hoptoada. Za pierwszym razem. Tylko za pierwszym. Każdy kolejny wyjątek z tej samej grupy (tak, hoptoad grupuje wyjątki) możemy zobaczyć poprzez interfejs www. Informacje są sformatowane, pogrupowane wg. “podsumowania”, środowiska i backtrace. Każdą grupę wyjątków możemy oznaczyć jako “resolved”, dzięki czemu mamy czystą i jasną listę błędów.

Społeczność developerów zobaczyła, że Hoptoad jest dobry i odwdzięczyła się – np. pluginem Exception Messaging, który wysyła info o błędach do Beanstalk. Mamy także makową aplikację napisaną w RubyCocoa  - Croak.app, która wyświetla nierozwiązane błędy. Hoptoad dzięki swojemu API dostał również pluginy do Merba, Javy i .NET.

Niestety, dostajemy kolejną warstwę, którą musimy się zajmować (nie dość, że odznaczymy ticket jako resolved – musimy odznaczyć go jeszcze w Hoptoadzie) – ale zyski jednak przeważają straty. Wspominałem już, że instalacja jest “dead simple”?… Zakładamy konto, instalujemy plugin do railsów, wklepujemy klucz api w naszą aplikację – i tyle. Polecam.

Debugowanie w Safari z nightly builds

Sunday, October 5th, 2008

Safari ciągle ma mały udział na rynku przeglądarek (2.7% użytkowników wg w3c na wrzesień 2008), lecz można śmiało powiedzieć, że w przypadku nowoczesnych aplikacji sieciowych ten procent jest większy. Ekipa odpowiedzialna za silnik WebKit ułatwiła nam ostatnio problem zadbania o poprawne wyświetalnie stron dzięki nowej wersji Web Inspectora – który stał się wbudowanym odpowiednikiem Firefoksowego Firebuga.

Dla pełnej listy zmian polecam przeczytać post na blogu WebKit – ja opiszę najważniejsze (z mojego punktu widzenia) ze zmian.

(more…)