Posted by Jarosław Zabiełło
Sat, 27 Jan 2007 03:33:00 GMT
W związku z przestawieniem się całkowicie na najnowszą wersję Railsów (1.2.1), postanowiłem przy zrobić także upgrade oprogramowania do mego bloga (który w wersji jaką miałem nie współpracował z RoR 1.2.1). Na szczęście, dzięki railsowym migracjom proces aktualizacji skryptów jak i struktury baz przebiegł bez problemów i niedestrukcyjnie dla danych w bazie. Typo”:http://trac.typosphere.org/ zawsze był kodem trochę awangardowym, wprowadzającym zaawansowane mechanizmy Rubiego i najnowsze pomysły Railsów. Przekonałem się o tym podczas próby modyfikacji paru szablonów. Typo zamiast dotychczasowego formatu ERb (*.rhtml) Typo używa już szablony nowej generacji – Haml. Chcąc niechcąc, musiałem przejść szybki kurs posługiwania się nimi aby zmodyfikować szablony w swoim blogu.
Read more...
Posted in Ruby on Rails | Tags erb, haml, rails, templates | 12 comments
Posted by Jarosław Zabiełło
Mon, 25 Dec 2006 00:14:00 GMT
W wypadku treści wyświetlanych w szablonach najlepiej zachować zasadę ograniczonego zaufania. Np. jeśli wyświetlamy zawartość komentarzy które ktoś wysłał z formularza, to przy odrobinie złośliwości i/lub głupoty taki użyszkodnik może nam wysłać kod HTML lub JavaScript, który popsuje spójność naszej strony. Generalnie istnieje kilka metod aby się przed tym zabezpieczyć.
- Wszelkie treści podejrzane o możliwość wysłania kodu HTML wyświetlaj przez funkcję filtrującą html_escape() (lub w skrócie: h) Czyli zamiast <= jakies_dane %> należy używać <=h jakies_dane %> i dobrze aby ten zwyczaj wszedł nam w krew. Dzięki temu helperowi wszelkie dane zawierające znaczniki zostaną wymienione na encje HTML (np. zamiast < będzie < co w efekcie uniemożliwi interpretację takich znaków jako tagów HTML)]
- W wypadku kiedy potrzebujemy kodu HTML, ale nie chcemy aby zawierał ukryte wstawki w języku JavaScript, dane filtrujemy przez funkcję sanitize(). Wszystkie akcje onXXX oraz linki zaczynające się od javascript: powinny zostać usunięte.
- W wypadku kiedy chcemy udostępnić użyszkodnikom możliwość wprowadzania treści z możliwością formatowania tekstu, zamiast HTML można udostępnić im możliwość wprowadzania tekstu w formacie Markdown (BlueCloth) lub Textile (RedCloth). To specjalny, uproszczony sposób formatowania tekstu, który jest zamieniany na bezpieczny i dobrze sformułowany kod HTML. Rails posiada wbudowane helpery do ich obsługi (są zdefiniowane w module ActionView::Helpers::TextHelper)
- Ostatecznie można wyciąć wszystkie znaczniki HTML za pomocą helpera strip_tags().
Aby Rails mógł używać helpery textilize() i markdown() trzeba je doinstalować
gem install RedCloth
gem install BlueCloth
Następnie w pliku config/environment.rb dodać kod:
require_gem 'RedCloth'
require_gem 'BlueCloth'
Przykład użycia:
<%= textilize '"Polskie forum":http://forum.rubyonrails.pl dla RoR.' %>
<%= markdown 'Strona Rubiego [po polsku](http://ruby-lang.org/pl).' %>
Wygenerowany kod HTML:
<p><a href="http://forum.rubyonrails.pl">Polskie forum</a> dla RoR.</p>
<p>Strona Rubiego <a href="http://ruby-lang.org/pl">po polsku</a>.</p>
Posted in Ruby on Rails | Tags rails | 1 comment
Posted by Jarosław Zabiełło
Sun, 24 Dec 2006 01:51:00 GMT
W Rails domyślnym miejscem do ustawienia swoich dodatkowych konfiguracji jest plik conf/environment.rb. Jednak wygodniejszym sposobem jest użycie formatu YAML. Np. załóżmy, że pliku config/defaults.yml mamy następujące ustawienia:
default: &defaults
paging: 10
development:
show_debugs: true
paging: 20
<<: *defaults
production:
show_debugs: false
<<: *defaults
Wykorzystałem tu zasadę DRY (unikania powtarzania kodu) stąd sekcja ‘default’ która zawiera wspólne ustawienia dla Railsów pracujących zarówno w trybie roboczym (developerskim) jak i produkcyjnym. Aby ten plik był wciągany i to zgodnie z bieżącym trybem pracy Railsów, do pliku config/environment.rb należy dodać:
require 'ostruct'
yml = YAML.load_file RAILS_ROOT + '/config/defaults.yml'
$defaults = OpenStruct.new(yml).send RAILS_ENV
Do naszej aplikacji RoR zostanie dodana zmienna globalna $defaults, W wypadku pracy w trybie produkcyjnym, zmienna $defaults zawiera hasz z wartościami:
{"paging"=>10, "show_debugs"=>false}
Zamiast użycia zmiennej globalnej, można użyć
::AppConfig = OpenStruct.new(yml).send RAILS_ENV
dzięki temu mamy dostęp do poszczególnych parametrów za pomocą notacji kropkowej:
Posted in Ruby on Rails | Tags rails | no comments
Posted by Jarosław Zabiełło
Thu, 14 Dec 2006 23:48:00 GMT
Nowy Skype 3 wprowadza małą rewolucję w stos. do poprzedniej wersji. Można nie tylko rozmawiać, ale pograć w szachy, kółko i krzyżyk i inne gry (są b. ładnie zrobione we Flashu 9). Można nagrywać rozmowy na dysk. Można tworzyć publiczne czaty. I właśnie w tej sprawie piszę ten tekst bo
stworzyłem polski czat dla miłośników frameworków Ruby on Rails, Django i Pylons.
Wygodniej jest czasem skonsultować coś w czasie rzeczywistym niż na grupie czy forum dyskusyjnym.
Posted in Ruby on Rails, Pylons, Python, Django (en), Ruby, Django | Tags django, pylons, rails | 17 comments
Posted by Jarosław Zabiełło
Fri, 01 Dec 2006 16:17:00 GMT
11 grudnia w Warszawie odbędzie się kolejne spotkanie dla osób zainteresowanych Ruby on Rails, rozwojem internetu i e-biznesem. Szczegóły tutaj.
Posted in Ruby on Rails | Tags meetings, rails | no comments
Posted by Jarosław Zabiełło
Wed, 29 Nov 2006 03:45:00 GMT

Drugie wydanie kultowej książki na temat Railsów jest już w druku. Wersja papierowa powinna być gotowa na 15 grudnia. Pierwsze wydanie zostało uznane za najlepszą książką techniczną na świecie. Drugie jest jeszcze ciekawsze, bo opisuje wszystkie nowości jakie mają się pojawić w Railsach 1.2. Właściciele wersji PDF mogą kupić wersję papierową ze zniżką.
Posted in Ruby on Rails | Tags rails | no comments
Posted by Jarosław Zabiełło
Sat, 25 Nov 2006 13:52:00 GMT
Nadchodzi wielkimi krokami Ruby on Rails 1.2. Właśnie udostępniono wersję RC1. Wersja finalna powinna pojawić się w najbliższych tygodniach. Wprowadzono szereg istotnych usprawnień w działaniu Railsów powiększając tym samym jeszcze bardziej komfort pracy i dystans w stosunku do pozostałych frameworków.
Np. dodano dodatkowy parametr “format” do metody respond_to. Aby z tego korzystać, należy w routes.rb dodać regułę:
map.connect ':controller/:action/:id.:format'.
Nie trzeba już więcej bawić się w analizę nagłówków HTTP.
class WeblogController < ActionController::Base
def index
@posts = Post.find :all
respond_to do |format|
format.html
format.xml { render :xml => @posts.to_xml }
format.rss { render :action => "feed.rxml" }
end
end
end
GET /weblog
GET /weblog.xml
GET /weblog.rss
Inną, istotną zmianą jest dodanie Multibyte. Nie jest to co prawda tak zaawansowane jak w Pythonie, ale do czasu pojawienie się Ruby 2 (który ma mieć pełne wsparcie dla Unicode), Multibyte poprawia trochę sytuację. programisty. Generalnie Ruby jakoś dawał sobie radę z UTF-8, ale w niektórych sytuacjach pojawiały się problemy. Np. metoda size() zwraca ilość bajtów a nie znaków. Multibyte wprowadza metodę proxy dla napisów – chars. Np.
Napisałeś <%= @post.body.chars.length %> znaków.
Jedną z bardziej rewolucyjnych zmian, jest dodanie obsługi REST. (która zakłada, że każdy zasób sieci powinien być jednoznacznie identyfikowany za pomocą samego adresu URL). W praktyce oznacza, to znacznie skrócenie kontrolerów w Railsach po przez wysłanie na ten sam adres różnych komend, tzn,. nie tylko GET i POST ale także PUT i DELETE. Mimo, że te polecenia są cześcią standardu protokołu HTTP, większość przeglądarek implementuje tylko GET I POST. W takim wypadku Rails emuluje działanie tych komend poprzez dodawanie do adresu znaku średnika i polecenia.
Plugin Simply RESTful już działa i można go używać. Np. wygeneruj sobie kod nowego, REST’owego scaffoldingu:
ruby script/generate scaffold_resource
Oczywiście, musisz mieć odpowiednią najnowszą wersję Railsów, którą najlepiej zainstalować za pomocą gemsów:
gem install rails --source http://gems.rubyonrails.org -y
Nie przejmuj się jak wyświetli ci się coś w stylu
Successfully installed rails-1.1.6.5618
To jest tymczasowe oznaczenie dla wersji RC1. Jak wyjdzie wersja finalna to będzie wyświetlać się numer 1.2.
Trwają jeszcze końcowe prace nad Active Resource, modułem obsługującym REST i nowy sposób mapowania.
I ostatnia wiadomość, nadchodzące w grudniu, drugie wydanie książki Agile Web Development in Rails powinno większość tych zmian uwzględniać, bo książka jest pisana z założeniem że używany jest Edge Rails (czyli najnowsza wersja z repozytorium SVN).
Posted in Ruby on Rails | Tags rails | 2 comments
Posted by Jarosław Zabiełło
Tue, 07 Nov 2006 23:47:00 GMT
W ostatnim artykule (Railsy: Lighttpd czy Apache 2.2.x?) porównywałem najbardziej popularne serwery HTTP dla Railsów. Zaintrygowany paroma wpisami w blogu postanowiłem przyjrzeć się dosyć mało znanemu serwerowi HTTP który zaczyna zdobywać coraz więcej uwagi na Zachodzie. Chodzi o ultraszybki serwer nginx napisany przez rosyjskiego programistę Igora Sysojewa.
Na pierwszy bój poszedł prosty test wyświetlenia “Hello World!” Na używanym przeze mnie serwerze dedykowanym (Athlon 64 3000+, 1GB RAM, Linux Ubuntu 64bit) dla 100 tys. zapytań (musiałem użyć aż tyle, bo serwer jest za szybki na mniejszą liczbę zapytań) uzyskałem następujące wyniki (dla polecenia “ab -n 100000 -c 1 http://localhost”):
- Apache 2.2.3 = 4439 req/s
- Lighttpd 1.4.11 = 7150 req/s
- Nginx 0.4.12 = 8700 req/s
Co prawda Nginx wykazuje miażdzącą przewagę wydajności nad Apachem ale, z racji tego, że używam Lighttpd, który co prawda odstaje od Nginxa ale nie aż tak, postanowiłem na razie zaczekać z ewentualną migracją.
Okazało się jednak, że będę musiał przeprowadzić taką migrację szybciej niż bym chciał. Coś złego zaczęło się dziać z Ligthttpd. Po paru godzinach pracy, przestawał odpowiadać na zapytania a nawet w ogóle proces znikał z pamięci. Ki diabeł? Trudno powiedzieć, nie mam czasu aby analizować dokładniej problem. Jedyne co pomagało to regularny restart Lighttpd. Trochę głupie rozwiązanie. Postanowiłem zatem zrobić wcześniejszą migrację do Nginxa. Wg statystyk Netcraftu z Nginxa korzysta już ponad 90 tys. domen. Wydaje się to wystarczającą ilością aby można było uznać ten serwer za stabilny.
Jednakże moja migracja ma pewną trudność. Używam bowiem równocześnie PHP, Django, Rails i Zope (ściślej: Plone). Czyli całkiem niezła mieszanka aplikacji. Z PHP i Railsami było najmniej problemów, bo przykłady konfiguracji są z grubsza podane w Wiki.
Z Plone było troszkę gorzej. Musiałem bowiem znaleźć odpowiednik mniej więcej takiego kodu w Apache:
RewriteRule "^/(.*)$"
"http://88.198.15.160:6001/VirtualHostBase/http/apologetyka.com:80/app/VirtualHostRoot/$1" [P,L]
To nie jest zwykły rewrite, to jest połączenie proxy z rewrite.
W Lighttpd (też się swego czasu namęczyłem aby to uzyskać) uzyskuje się to tak:
url.rewrite-once = (
"^/(.*)$" => "/VirtualHostBase/http/apologetyka.com:80/plone/VirtualHostRoot/$1"
)
proxy.server = (
"/VirtualHostBase/" => (
( "host" => "88.198.15.160" , "port" => 6001 ) )
)
Trochę prób i się udało. Nginx potrzebował takiego wpisu:
location / {
rewrite ^/(.*)$ /VirtualHostBase/http/apologetyka.com:80/plone/VirtualHostRoot/$1;
}
location /VirtualHostBase/ {
include /opt/nginx/conf/proxy.conf;
proxy_pass http://88.198.15.160:6001;
}
Najtrudniej było z konfiguracją Django bo opisu do Django na Nginx nie ma ani w dokumentacji do Django, ani w dokumentacji do NGinxa. Zmęczony eksperymentowaniem napisałem na listę dyskusyjną Django i dostałem całkiem pożyteczną wskazówkę odnośnie strony http://www.python.rk.edu.pl/w/p/django-pod-serwerem-nginx/. Niestety miałem pecha, bo akurat trafiłem na zmianę wpisów w DNS i artykuł był niedostępny. Udało mi się na szczęście wyłuskać jego kopię z cache Googli. Autor międzyczasie podesłał mi też pliki z artykułami. Zauważyłem że napotkał pewne problemy ze zmuszeniem Django do wyświetlania statycznej treści. Trochę podłubałem w kodzie i problem rozwiązałem. :)
Zauważyłem że Django wyświetlał mi pliki statyczne w trybie debug. Wynikało to pewnie z tego, że w urls.py stosuję zawsze taki wpis:
...
if DEBUG:
urlpatterns += patterns('',
(r'^images/(?P<path>.*)$', 'django.views.static.serve', {'document_root': MEDIA_ROOT+'/images', 'show_indexes': True}),
(r'^stylesheets/(?P<path>.*)$', 'django.views.static.serve', {'document_root': MEDIA_ROOT+'/stylesheets', 'show_indexes': True}),
(r'^javascripts/(?P<path>.*)$', 'django.views.static.serve', {'document_root': MEDIA_ROOT+'/javascripts', 'show_indexes': True}),
)
Dla trybu produkcyjnego (settings.DEBUG=False) trzeba zmusić serwer HTTP aby się zajmował plikami statycznymi. Django ma tylko przetwarzać Pythona. Mozna to zrobić np. tak:
...
location ~* ^.+\.(jpg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|doc|xls|exe|pdf|ppt|txt|tar|mid|midi|wav|bmp|rtf|js|mov) {
access_log off;
expires 30d;
}
location / {
include /opt/nginx/conf/fastcgi.conf;
fastcgi_pass 127.0.0.1:6002;
fastcgi_pass_header Authorization;
fastcgi_intercept_errors off;
}
Gdzie plik fastcgi.conf:
fastcgi_param GATEWAY_INTERFACE CGI/1.1;
fastcgi_param SERVER_SOFTWARE nginx;
fastcgi_param QUERY_STRING $query_string;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_param REQUEST_URI $request_uri;
fastcgi_param DOCUMENT_URI $document_uri;
fastcgi_param DOCUMENT_ROOT $document_root;
fastcgi_param SERVER_PROTOCOL $server_protocol;
fastcgi_param REMOTE_ADDR $remote_addr;
fastcgi_param REMOTE_PORT $remote_port;
fastcgi_param SERVER_ADDR $server_addr;
fastcgi_param SERVER_PORT $server_port;
fastcgi_param SERVER_NAME $server_name;
fastcgi_param PATH_INFO $fastcgi_script_name;
Plik startowy napisałem sobie już w Pythonie:
import os, sys, time
DEBUG = True
path = '/home/app/django'
projects = {
'biblia' : {
'project': 'searchers',
'port':6002,
'pidfile': '/var/run/django_searchers.pid',
'children': 4,
},
'koran': {
'project': 'django_project',
'port':6003,
'pidfile': '/var/run/django_koran.pid',
'children': 4
},
}
def start(name):
project = projects[name]['project']
os.chdir('%s/%s/' % (path, project))
appl = './manage.py runfcgi host=127.0.0.1'
cmd = '%s port=%s minspare=1 maxspare=%s pidfile=%s --settings=%s.settings' \
% (appl, projects[name]['port'], projects[name]['children'], projects[name]['pidfile'], project)
if DEBUG: print cmd
os.system(cmd)
def stop(name):
pidfile = projects[name]['pidfile']
if os.path.exists(pidfile):
cmd = '/bin/kill -TERM %s' % open(pidfile).read()
if DEBUG: print cmd
os.system(cmd)
os.unlink(pidfile)
def restart(name):
stop(name)
time.sleep(1)
start(name)
if __name__ == '__main__':
try:
action, project = sys.argv[1], sys.argv[2]
if action in ['start','stop', 'restart'] and project in projects:
if action == 'start':
start(project)
elif action == 'stop':
stop(project)
elif action == 'restart':
restart(project)
else:
raise IndexError
else:
raise IndexError
except IndexError:
print "Usage: %s {start|stop|restart} {%s}" % (sys.argv[0], '|'.join(projects.keys()))
Migracja się udała. Plone, PHP, Django i Rails śmigają mi teraz na ultraszybkim (i zajmującym mało pamięci!) serwerze Nginx. Acha, zapomniałem dodać: Nginx to nie tylko duża wydajność i oszczędność pamięci. Nginx ma dużo modułów. Może nie tyle, co Apache, ale znacznie lepiej niż Lighttpd.
BTW, ciekawie wygląda także serwer Cherokee. Nginx działa tylko pod systemami POSIX (Unix, MacOS-X, Linux, FreeBSD). Cherokee natomiast posiada… binarną instalację pod Windows! Ale o tym może napiszę coś innym razem. :)
Posted in Ruby on Rails, Django | Tags cherokee, django, fastcgi, nginx, rails | 13 comments
Posted by Jarosław Zabiełło
Tue, 07 Nov 2006 23:13:00 GMT
RadRails, zintegrowany edytor dla Rubiego i Railsów zaczyna coraz bardziej niwelować wcześniejsze zachwyty nad komercyjnym edytorem TextMate. Nie dość, że jest darmowy i działa na Windows, MacOS-X i Linuksie (TextMate tylko na MacOS-X), to na dodatek uzyskał to, co do tej pory było główną atrakcją TextMate – makra przyśpieszające pisanie kodu, czyli tzw. snippety. RadRaila ma już przygotowanych 199 snippetów do Rubiego i 50 do RHTML!
Do tego wystarczy dorzucić kolorowanie kodu a’la TextMate i RadRails ma już wszystko (no może do pełni doskonałości brakuje mu uzupełniania kodu tak, jak to robi komercyjny edytor Komodo)
Posted in Ruby on Rails, Ruby | Tags edytory, radrails, rails, ruby | no comments
Posted by Jarosław Zabiełło
Sun, 29 Oct 2006 14:53:00 GMT
Odnośnie użycia Railsów w celu produkcyjnym, dużo się zmieniło od czasu pojawienia się Mongrela – małego, ale dosyć szybkiego serwera napisanego w Ruby i C. Następuje generalne odejście od podpinania kilku procesów FastCGI do Rubiego z różnych powodów. W drugim wydaniu Agile Web Development in Rails autorzy przyznali, że próbowali różnych opcji użycia modułu FastCGI. Zawsze ostatecznie były jakieś problemy.
Aktualnie zalecanym podejściem jest użycie szybkiego serwera HTTP (Lighttpd, Apache lub LiteSpeed) na froncie do obsługi statycznych plików (głównie obrazki, style kaskadowe i pliki Javascript). Aplikację RoR należy uruchomić za pomocą kilku procesów Mongrela (nie jak wcześniej: kilka procesów FastCGI). A tym, co zepnie je z serwerem HTTP jest moduł rozkładający ruch (load balancing).
Niestety, okazało się że w wypadku Lighttpd ten moduł zawiera błędy. Z kolei nowy Apache 2.2 posiada dobrze działający moduł load balancingu. Spowodowało to zrezygnowanie przez wielu z Lighttpd na rzecz nowego Apache 2.2.x.
Z racji tego, że mam trochę swobody w doborze technologii w pracy, postawiłem serwer na nowym Apache’u. Aplikacje Railsów podpinamy za pomocą mongrela i wbudowanego w Apache modułu load_balancer. Działa faktycznie sprawnie.
Czy to znaczy, że Lighttpd nie ma sensu używać? Skąd! W wersji 1.5 mają już mieć naprawiony moduł load balancingu. Ale nawet i bez tego, istnieje bardzo dobry, mały i szybki load balancer – Pound. Skuszony jednak potrzebą eksperymentowania oraz nabytym niedawno serwerem dedykowanym (w miejsce wcześniejszego VPS’a) postanowiłem przenieść wszystkie swoje prywatne serwisy (a jest tego sporo) z Lighttpd do Apache 2.2.3. Musiałem przenieść dwie aplikacje Rails, dwie aplikacje Django, dwie aplikacje PHP 5.1 oraz jedną duża aplikację Zope/Plone. I jak wrażenia?
Otóż, po 2 tygodniach używania, stwierdziłem, że to nie ma sensu. Apache pożera za dużo pamięci. Dzieje się dokładnie tak, jak pisałem wcześniej. Nie mogłem użyć trybu wielowątkowego, nie tyle ze względu na PHP ale ze względy na Django! Napisali bowiem, że nie należy tego trybu używać w wypadku ich frameworka. Django nie jest wielowątkowy. Musiałem więc przełączyć Apache z trybu worker na prefork. Zgodnie z obawami, każdy fork musiał marnować pamięć na moduł mod_php i mod_python nawet jak to nie ma sensu (np. podczas obsługi obrazków). Na dodatek nie mogłem coś uruchomić jednej aplikacji Django. Kompletnie nie wiem dlaczego. Druga była prawie identycznie skonfigurowana i działała.
Wróciłem zatem z powrotem do Lighttpd , Pounda i Mongrela (dla RoR) i FastCGI (dla Django i PHP). Efekty były bardzo widoczne: zwolniło mi się ponad 200 MB pamięci. Może to nie ma znaczenia w pracy, gdzie mamy 2GB ale ja mam tylko 1GB i muszę jeszcze uruchomić zasobożerny Plone.
Dokładniej wszystkie sprawdzone i działające konfiguracje opiszę w powstającej książce o Railach. Moja ostateczna konlkluzja jest taka: jeśli zależy ci na oszczędzeniu pamięci – wybieraj Lighttpd. Jeśli nie jest to kluczowa sprawa, a potrzebujesz jakieś specjalne, dodatkowe moduły (których Apache ma pełno) nowy Apache 2.2 spełni twe oczekiwania.
Posted in Ruby on Rails | Tags apache, fastcgi, lighttpd, mod_python, rails | 6 comments