<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Rubysfera &#187; Tutoriale</title>
	<atom:link href="http://rubysfera.pl/category/tutoriale/feed/" rel="self" type="application/rss+xml" />
	<link>http://rubysfera.pl</link>
	<description>Kolejna witryna oparta na WordPressie</description>
	<lastBuildDate>Wed, 02 May 2012 19:17:19 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>Git &#8211; zaawansowany diff, status &amp; log</title>
		<link>http://rubysfera.pl/2012/01/git-zaawansowany-diff-status-log/</link>
		<comments>http://rubysfera.pl/2012/01/git-zaawansowany-diff-status-log/#comments</comments>
		<pubDate>Tue, 24 Jan 2012 15:10:54 +0000</pubDate>
		<dc:creator>Maciej Gajewski</dc:creator>
				<category><![CDATA[Tutoriale]]></category>

		<guid isPermaLink="false">http://rubysfera.pl/?p=1095</guid>
		<description><![CDATA[Korzystasz z <strong>gita</strong>, ale chciałbyś z niego wycisnąć więcej? Dziś mamy dla Ciebie zaawansowane porady odnośnie <strong>git diff</strong>, <strong>git status</strong> i <strong>git log</strong>.  Zebrane przez Maćka Gajewskiego (<a href="https://twitter.com/#!/@weszlem">@weszlem</a>).]]></description>
			<content:encoded><![CDATA[<p><a href="http://rubysfera.pl/2012/01/git-zaawansowany-diff-status-log/git/" rel="attachment wp-att-1524"><img src="http://rubysfera.pl/wp-content/uploads/2012/01/git.png" alt="" title="git" width="256" height="256" class="alignright size-full wp-image-1524" /></a>Trudno sobie wyobrazić średni czy duży projekt, którym dało by się zarządzać bez pomocy systemu kontroli wersji. Z różnych przyczyn (<a href=https://github.com/">GitHub</a>!), nieoficjalnym standardem w środowisku programistów Rails stał się Git.</p>
<p>Git jest potężnym narzędziem. Potężnym w podobny sposób jak potężny jest Emacs albo VIM. Git tak jak Emacs czy VIM potrafi przysporzyć kłopotu z najprostszymi czynnościami. Wiele osób korzysta z Gita nie rozumiejąc jego filozofii i znając tylko podstawowe polecenia, tak jak wiele osób korzysta z VIMa używając tylko <code>&lt;ESC&gt;:wq</code> oraz <code>i</code>. Komendy w gicie posiadają setki możliwych kombinacji argumentów. Część komend nazwana jest tak, żeby za nic nie dało się zgadnąć do czego służą (Emacs &#8222;auto-fill-mode&#8221; anybody?).</p>
<p>Wszystkie te programy po przeskoczeniu początkowych trudności, związanych z nauką nowego sposobu myślenia, powodują znaczny wzrost produktywności u użytkownika.</p>
<p>Jest jeszcze jedna rzecz łącząca Gita z VIMem i Emacsem. Wiele osób nie wie o istnieniu monstrualnej ilości trików pozwalających przyspieszyć i uprzyjemnić swoją pracę z tymi programami. Są to zwykle &#8222;sztuczki&#8221; rozwiązujące konkretny drobny problem. Na tyle drobny, że osobie napotykającej na niego nie opłaca się szukać bezpośredniego rozwiązania, więc zwykle problem zostaje rozwiązany &#8222;na około&#8221;.</p>
<p>Postanowiłem zebrać w jednym miejscu kilka takich &#8222;sztuczek&#8221;.</p>
<h3>diff</h3>
<p>Jedną z najprzydatniejszych komend w każdym porządnym systemie kontroli wersji jest <code>diff</code>.</p>
<p>Git pozwala porównać ze sobą pliki, commity, branche.</p>
<p>Nie wszyscy jednak wiedzą, że gitowy diff przyjmuje wiele opcji konfigurujących sposób w jaki różnice zostaną wyświetlone na ekranie. Jedną z nich jest <strong>&#8211;word-diff</strong>.</p>
<p>Typowy przypadek użycia tego przełącznika to np. próba wyświetlenia drobnych zmian w bardzo długiej linii. Problem ze zwykłym diffem jest taki, że zmiany zostaną pokazane linia do linii.</p>
<pre>
<code>git diff</code>

<code>def too_big_if_to_be_true
-    some_very_long_method_name arg_firct, arg_second
+    some_very_long_method_name arg_first, arg_second
end</code>
</pre>
<p>Patrząc na powyższy kod nie widać od razu co zostało zmienione i na co. Z pomocą przychodzi<strong> &#8211;word-diff</strong>. Po dodaniu tego przełącznika do wywołania git diff otrzymamy następujący rezultat:</p>
<pre>
<code>git diff --word-diff</code>

<code>def too_big_if_to_be_true
some_very_long_method_name [-arg_firct,-]{+arg_first,+} arg_second
end</code>
</pre>
<p>W tym wypadku sytuacja wygląda trochę lepiej. Nawias kwadratowy i znaki &#8216;-&#8217; pokazują nam zastępowany wyraz, nawias klamrowy i znaki &#8216;+&#8217; pokazują wyraz zastępujący. Wciąż nie jest to jednak forma najbardziej czytelna, szczególnie jeśli trafi nam się kawałek kodu, w którym intensywanie korzystamy z tablicy ([]) albo hasha ({}). W tym wypadku sprawdza się flaga <strong>&#8211;color-words</strong>:</p>
<pre>
<code>git diff --color-words</code>

<code>def too_big_if_to_be_true
some_very_long_method_name <span style="color: red">arg_firct</span>,<span style="color: green">arg_first</span>, arg_second
end</code>
</pre>
<p>Jeśli odpalimy tą komendę w terminalu, który obsługuje kolory, jakiekolwiek wątpliwości co do wprowadzonych zmian zostaną natychmiast rozwiane. Wyraz zastępowany zostaje pokolorowany na czerwono, wyraz zastępujący na zielono.<br />
Istnieje również możliwość połączenia <strong>&#8211;word-diff</strong> z kolorowaniem:</p>
<pre>
<code>git diff --word-diff --color</code>

<code>def too_big_if_to_be_true
some_very_long_method_name <span style="color: red">[-arg_firct,-]</span><span style="color: green">{+arg_first,+}</span> arg_second
end</code>
</pre>
<p>Oczywiście nie ma sensu za każdym razem wpisywać ręcznie <strong>&#8211;word-diff</strong>. Od czego mamy aliasy:</p>
<pre>
<code>git config alias.dic 'diff --color-words'</code>
</pre>
<p>ustawia alias &#8216;dic&#8217; działający w bieżącym repozytorium. Jeśli dodamy <strong>&#8211;global</strong>:</p>
<pre>
<code>git config --global alias.dic 'diff --color-words'</code>
</pre>
<p>zmiany zostaną zapisane w naszym pliku .gitconfig, przez co będą działały również w pozostałych repozytoriach.</p>
<h3>status</h3>
<p>Dużą pomocą dla początkujących użytkowników gita jest wiadomość pokazująca się każdorazowo podczas odpalenia komendy <strong>status</strong>. Poniżej widać przykładowe wywołanie git status w repozytorium, w którym został zmieniony tylko jeden plik.</p>
<pre>
<code>git status</code>
<code>
# On branch master
# Changes not staged for commit:
#   (use "git add &lt;file&gt;..." to update what will be committed)
#   (use "git checkout -- &lt;file&gt;..." to discard changes in working directory)
#
#    modified:   app/controllers/application_controller.rb
#
no changes added to commit (use "git add" and/or "git commit -a")</code>
</pre>
<p>Jak widać więcej niż same zmiany w repozytorium zajmuje tekst objaśniający co z tymi zmianami można zrobić, jak je cofnąć, jak wykonać commit. Ten widok, uszyty specjalnie dla początkujących, nie jest jedynym możliwym sposobem wyświetlenia statusu zmian.</p>
<p>Z pomocą przychodzi opcja <strong>&#8211;short</strong> (w skrócie <strong>-s</strong>). Jej użycie powoduje, że zamiast wielkiego tekstowego bloba pojawia się zgrabne:</p>
<pre>
<code>git status -s</code>
<code>
M app/controllers/application_controller.rb</code>
</pre>
<p>Jeśli nie mamy ustawionego wyświetlania bieżącego brancha w shellu warto jeszcze dodać przełącznik <strong>&#8211;branch</strong>. Dzięki niemu na górze wyświetlą się informacje na temat bieżącego brancha.</p>
<pre>
<code>git status -sb</code>
<code>## master
M app/controllers/application_controller.rb</code>
</pre>
<p>Można ułatwić sobie życie i dodać powyższą komendę jako alias.</p>
<pre>
<code>git config --global alias.st 'status -sb'</code>
</pre>
<h3>log</h3>
<p>Jedną z częściej używanych, a przy tym mocno niedocenianych komend, jest w gicie <strong>log</strong>. Większość z nas w normalnej pracy ogranicza się do odpalenia git <strong>log</strong> bez parametrów, ew. z nazwą pliku, którego log chcemy zobaczyć. <strong>git-log</strong> to idealny przykład komendy, która w 90% przypadków robi dokładnie to czego od niej oczekujemy bez żadnej pomocy z naszej strony. Na pozostałe 10% przypadków twórcy gita przygotowali mnóstwo opcji pozwalających nam zdecydować co właściwie chcemy zobaczyć, w jakim formacie i w jakiej kolejności.</p>
<p>git-log domyślnie wypisuje historię zmian dokonanych na danym branchu w formacie <strong>HASH</strong>, <strong>AUTOR</strong>, <strong>DATA</strong>, <strong>COMMIT_MESSAGE</strong>.</p>
<p>Tak naprawdę najbardziej interesujące w logu są treści commitów. Nie zawsze jednak same teksty wystarczają do znalezienia tego czego szukamy (kto nigdy nie wpisał bzdurnego <strong>COMMIT_MESSAGE</strong> niech pierwszy rzuci kamień!).</p>
<p>Bardzo przydana jest możliwość wypisania nie tylko samych commitów, ale także pokazania ich zawartości w formie patchy. Służy do tego polecenie:</p>
<pre>
<code>git log -p</code>

<code>
commit 69dc58e59f11436b4a153537f63d7db3baa8552e
Author: Maciej Gajewski &lt;email&gt;
Date:   Fri Sep 16 16:24:34 2011 +0200</code>

<code>Message 1</code>
</pre>
<pre>
<code>diff --git a/abc b/abc
index 11921d5..d8a2f87 100644
--- a/abc
+++ b/abc
@@ -1,3 +1,7 @@
Master</code>
<code>
Master end
+
+Master 1
+
+Master 2
</code>
<code>
commit aa1d275d9c9cba634297c864301238c6903c5e08
Author: Maciej Gajewski &lt;email&gt;
Date:   Fri Sep 16 16:23:08 2011 +0200

<code>added to master</code>

diff --git a/abc b/abc
index e69de29..11921d5 100644
--- a/abc
+++ b/abc
@@ -0,0 +1,3 @@
+Master
+
+Master end
</code>
</pre>
<p>Odpalone bez parametrów pokaże nam logi bieżącego brancha łatka po łatce, co kiedy zostało dodane i przez kogo. Jeśli wpiszemy po <strong>-p</strong> nazwę pliku będziemy mogli zobaczyć zmiany w podanym pliku &#8211; poprawka po poprawce.</p>
<p>Zdarzają się sytuacje, że <strong>log -p</strong> zwraca za dużo informacji. Czasami chcemy po prostu zobaczyć <strong>jakie</strong> pliki były zmieniane, a nie koniecznie każdą jedną zmianę w nich. W tym celu musimy odpalić <strong>git-log</strong> z parametrem <strong>&#8211;stat</strong></p>
<pre>
<code>
commit 78dbfbe86609759c33f9c59362f6a2813d2c3e13
Author: Maciej Gajewski &lt;mail&gt;
Date:   Fri Sep 16 16:28:53 2011 +0200</code>

<code>Added config and index files</code>
<code>
config.xml |    9 +++++++++
index.html |   17 +++++++++++++++++
2 files changed, 26 insertions(+), 0 deletions(-)
</code>
<code>
commit fa0950503af962cccdccd1bcb9b9380501faed28
Author: Maciej Gajewski &lt;mail&gt;
Date:   Fri Sep 16 16:27:36 2011 +0200
</code>
<code>
Added main ruby file
</code>
<code>
main.rb |    3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
</code>
</pre>
<p>Git-Log pozwala nam na na wyświetlenie listy zmian na wszystkich branchach, nie tylko na bieżącym. Co więcej, możemy wyświetlić zmiany tylko na niektórych branchach.</p>
<p>Na przykład:</p>
<pre>
<code>git log b1 b2</code>
</pre>
<p>wyświetli wszystkie commity, które występują na branchu b1 i te które występują na branchu b2.<br />
Niezwykle przydaje się możliwość wyświetlenia commitów, które znajdują się na jednym branchu, ale nie ma ich jeszcze na drugim.<br />
Pisząc:</p>
<pre>
<code>git log master..b1</code>
</pre>
<p>możemy zobaczyć które commit są na branchu b1, ale nie zostały jeszcze zmergowane do mastera.</p>
<p>Git potrafi filtrować historię po dacie.</p>
<pre>
<code>
git log --since=2.hours.ago --until=10.minutes.ago</code>
</pre>
<p>Co robi powyższy kod jest w miarę jasne. Wyświetla wszystkie commity powstałe najwyżej dwie godziny temu i nie później niż dziesięć minut temu. Zamiast hours i minutes można wstawić m.in. days, years, months, weeks itd.</p>
<p>Na koniec zostawiłem coś o co chyba najczęściej pojawiają się pytania w kontekście polecenia &#8222;log&#8221;.</p>
<pre>
<code>git log -S "def login"</code>
</pre>
<p>wyświetli wszystkie commity, które zawierają &#8222;def login&#8221;. Zawierają nie w COMMIT_MESSAGE tylko w plikach dodanych w konkretnym commicie.</p>
<h3>Szukania ciąg dalszy</h3>
<p>Załóżmy, że mamy jakąś zmianę ale nie wiemy na ilu gałęziach ona się znajduje. Ten problem rozwiązuje git-brach &#8211;contains.</p>
<pre>
<code>git branch --contains=8d38c3ec11ee6247ff929f264815b3f508fc47b2
b1
b2
* master</code>
</pre>
<p>Polecenie to wypisuje nazwy branchy na których znajduje się commit o podanym SHA1.</p>
<p>Wszystkie powyższe argumenty można łączyć, a więc możliwe jest znalezienie np. definicji funkcji dodanej w zeszłym tygodniu przez autora A, która nie została jeszcze z mergowana z masterem. Nie jest ważne, żeby nauczyć się koniecznie tych poleceń na pamięć (chociaż warto!). Najważniejsze jest żeby wiedzieć, że git posiada takie możliwości. Po detale można sięgać w razie potrzeby <img src='http://rubysfera.pl/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<h3>Dla wzrokowców</h3>
<p>Na koniec tej sekcji bonus. Jeśli nie znasz jeszcze &#8211; wpisz do konsoli w swoim największym projekcie <img src='http://rubysfera.pl/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<pre>
<code>git log --oneline --graph</code>
</pre>
<p>Aha! Istnieje jeszcze jeden &#8222;hack&#8221; pasujący do kategorii &#8222;log&#8221; chociaż nie mający z git-log wiele wspólnego.</p>
<pre>
<code>git show :/regexp</code>
</pre>
<p>znajduje i wyświetla ostatni commit które COMMIT_MESSAGE pasuje go wzorca regexp.</p>
<p>Takich trików jest naprawdę mnóstwo i naprawdę warto się zabrać za solidną naukę obsługi gita. To się opłaca. </p>
]]></content:encoded>
			<wfw:commentRss>http://rubysfera.pl/2012/01/git-zaawansowany-diff-status-log/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>10 porad o&#8230; RVM</title>
		<link>http://rubysfera.pl/2011/09/10-porad-o-rvm/</link>
		<comments>http://rubysfera.pl/2011/09/10-porad-o-rvm/#comments</comments>
		<pubDate>Wed, 28 Sep 2011 08:27:53 +0000</pubDate>
		<dc:creator>tjeden</dc:creator>
				<category><![CDATA[Tutoriale]]></category>

		<guid isPermaLink="false">http://rubysfera.pl/?p=1260</guid>
		<description><![CDATA[Z serii <strong>"10 porad o..."</strong> dziś sporo ciekawych wskazówek dotyczących używania <strong>RVM</strong>  - najbardziej popularnego menadżera do zarządzania wersjami Rubiego.]]></description>
			<content:encoded><![CDATA[<p><a href="http://rubysfera.pl/2011/09/10-porad-o-rvm/rvm_main/" rel="attachment wp-att-1286"><img src="http://rubysfera.pl/wp-content/uploads/2011/09/rvm_main.png" alt="" title="rvm_main" width="300" height="139" class="alignright size-full wp-image-1286" /></a>
<p><a href="http://beginrescueend.com/">RVM</a> to narzędzie, bez którego ciężko sobie wyobrazić pracę z Rubym. Począwszy od instalacji języka, przez szybkie i wygodne przełącznie się między różnymi konfiguracjami, a na eksperymentowaniu z najnowszymi wydaniami kończcc. Oto 10 porad, które przydadzą się przy codziennej pracy z RVM. Jeśli nie wiesz dlaczego warto korzystać z RVM, zajrzyj do artykułu opisującego <a href="http://rubysfera.pl/2010/09/warte-uwagi-rvm/">Ruby Virtual Machine</a>.</p>
<h3>1. .rvmrc</h3>
<p>Plik <code>.rvmrc</code> uważam za niezbędny w codziennej pracy z RVM. Jeśli w dowolnym katalogu umieścisz plik <code>.rvmrc</code>, to przy wejściu do tego katalogu, automatycznie zostanie załadowana odpowiednia wersja rubiego i gemset. Bardzo szybko można utworzyć taki plik poleceniem:</p>
<pre>echo 'rvm use 1.9.2@projekt_x' > .rvmrc</pre>
<p>Utworzony zostanie plik o zawartości:</p>
<pre>rvm use 1.9.2@projekt_x</pre>
<p>Teraz przy każdym wejściu do tego katalogu ładowana będzie wersja rubiego 1.9.2 z gemsetem projekt_x.</p>
<h3>2. Globalny gemset</h3>
<p>Zazwyczaj dla każdego projektu tworzę osobny gemset, zazwyczaj potrzebuję wtedy bundlera, by zainstalować potrzebne gemy, niestety bundlera trzeba za każdym razem instalować wcześniej ręcznie. RVM dostarcza globalnych gemsetów, dla każdego zainstalowanego intepretera. Użycie komend:</p>
<pre>rvm use gemset global
gem install bundler</pre>
<p>sprawi, że w każdym gemsecie w danej wersji rubiego bundler będzie dostępny.</p>
<h3>3. Importowanie/eksportowanie gemsetów</h3>
<p>Jeśli chcesz stworzyć zapisać aktualny gemset, możesz wyeksportować listę gemów do pliku. Możliwe jest kilka sposobów.</p>
<pre>
# eksportuje aktualny gemset do pliku defaults.gem
rvm gemset export     

# eksportuje konkrenty gemset do pliku projekt_x.gem
rvm 1.9.2@projekt_x   

# eksportuje aktualny gemset do pliku projekt_x.gem
rmv gemset export projekt_x.gem
</pre>
<p>Importowanie pliku jest zgodne z konwencją:</p>
<pre>
rvm gemset import projekt_x
</pre>
<p>Polecenie to zaimportuje gemy z pliku <code>projekt_x.gems</code> do aktualnego gemsetu.</p>
<h3>4. Kopiowanie gemsetów między róznymi wersjami Rubiego</h3>
<p>Kopiowanie może się odbyć również bez importowania i eksportowania. Wystarczy jedno polecenie.</p>
<pre>rvm gemset copy 1.8.7@rails3 1.9.2-head@rails3</pre>
<h3>5. Rubinius i inne wersje Rubiego.</h3>
<p>RVM daje Ci szansę bezproblemowego zainstalowania rzedziej używanych wersji, takich jak Rubinius, lub Jruby. Wpisz:</p>
<pre>rvm install rbx</pre>
<p>I zobacz jak twój projekt zachowuje się z Rubiniusem, tak to jest takie proste. Pełna lista obsługiwanych interpreterów dostępna jest na <a href="http://beginrescueend.com/interpreters/">oficjalnej stronie RVM</a>.</p>
<h3>6. Haki (hooks)</h3>
<p>Możliwe jest zdefiniowanie akcji, które zostaną wywołane przed i po określonych komendach RVMa, takich jak <code>after_use before_install, after_install, after_do oraz after_cd</code>. Na przykład można utworzuć plik <code>~/.rvm/hooks/after_install</code> z zawartością:</p>
<pre>echo "Ścieżka interpretera $rvm_ruby_home"</pre>
<p>Skrypt ten zostanie wywołany po każdym zainstalowaniu nowej wersji Rubiego. Korzysta on ze zmiennej środowiskowej <code>$rvm_ruby_home</code> (<a href="http://beginrescueend.com/workflow/hooks/">pełna lista zmiennych dla RVM wraz z opisami</a>).</p>
<h3>7. Uruchamianie programów (i testów) na wielu wersjach Rubiego</h3>
<p>Jeśli mamy program <code>pinkie_pie.rb</code>, następująca komenda uruchomi go na wszystkich zainstalowanych wersjach Rubiego.</p>
<pre>rvm ruby pinkie_pie.rb</pre>
<p>Możliwe jest ograniczenie wykonywania do konkretnych wersji. Jeśli chcemy sprawdzić tylko 1.9.2 i Rubinusa, to piszemy:</p>
<pre>rvm 1.9.2,rbx ruby pinkie_pie.rb</pre>
<p>Jest to szczególne przydatne przy odpalaniu testów (np. do sprawdzania pod jakimi wersjami działa Twój gem):</p>
<pre>rvm rake test</pre>
<p>Możliwe jest ustalenie formatu raportu przy pomocy opcji <code>--json</code> oraz <code>--yaml</code>. Oczywiście działa to też z Rspeckiem.</p>
<h3>8. Przydatne komendy</h3>
<p>Można użyć konkrentego gemsetu i przy okazji stworzyć plik <code>.rvmrc</code>:</p>
<pre>rvm use 1.9.2@rails3 --rvmrc</pre>
<p>Krok dalej. Stworzenie gemsetu wraz z plikiem <code>.rvmrc</code>:</p>
<pre>rvm --create --rvmrc 1.9.2@projekt_x</pre>
<p>Instalacja gemów dla różnych wersji Rubiego naraz:</p>
<pre>rvm 1.8.7,1.9.2 gem install rails</pre>
<p>Aby automatycznie tworzyć gemset przy pierwszym użyciu można w pliku <code>~/.rvmrc</code> ustawić następującą flagę:</p>
<pre>rvm_gemset_create_on_use_flag=1</pre>
<h3>9. Graficzna nakładka</h3>
<p><a href="http://rubysfera.pl/2011/09/10-porad-o-rvm/main_menu/" rel="attachment wp-att-1283"><img src="http://rubysfera.pl/wp-content/uploads/2011/09/main_menu.png" alt="" title="main_menu" width="305" height="315" class="alignright size-full wp-image-1283" /></a></p>
<p>Ostatnio powstało GUI do RVM, <a href="http://jewelrybox.unfiniti.com/">dostępne tylko na OS X</a>. Co prawda jest bardzo ładne, ale skoro przebrneliście przez ten artykuł, to raczej nie powinno być wam potrzebne.</p>
<h3>10. Alternatywa</h3>
<p>Jeśli z jakichś względów RVM Ci nie odpowiada, zawsze możesz użyć lżejszego narzędzia o nazwie <a href="https://github.com/sstephenson/rbenv">Rbenv</a>. Osobiście nie widzę powodu by z niego korzystać.</p>
<p>Macie do dodania inne ciekawe rady odnośnie RVM?</p>
]]></content:encoded>
			<wfw:commentRss>http://rubysfera.pl/2011/09/10-porad-o-rvm/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Ajaxowe dodawanie nowego rekordu</title>
		<link>http://rubysfera.pl/2011/05/ajaxowe-dodawanie-nowego-rekordu/</link>
		<comments>http://rubysfera.pl/2011/05/ajaxowe-dodawanie-nowego-rekordu/#comments</comments>
		<pubDate>Wed, 25 May 2011 08:27:08 +0000</pubDate>
		<dc:creator>slawosz</dc:creator>
				<category><![CDATA[Tutoriale]]></category>

		<guid isPermaLink="false">http://rubysfera.pl/?p=907</guid>
		<description><![CDATA[W dzisiejszym artykule pokażemy jak łatwo stworzyć ajaxową alternatywę dodawania nowego rekordu - post gościnny <a href="https://github.com/slawosz">Sławosza Sławińskiego</a>.
]]></description>
			<content:encoded><![CDATA[<p>W dzisiejszym artykule pokażemy jak łatwo stworzyć ajaxową alternatywę dodawania nowego rekordu.﻿﻿<br />
<img class="alignleft size-full wp-image-948" src="http://rubysfera.pl/wp-content/uploads/2011/05/ajax.png" alt="" width="300" height="200" /><br />
W <a href="http://railscasts.com/episodes/258-token-fields">Railscaście 258</a> Ryan Beats zademonstrował użycie <a href="http://loopj.com/jquery-tokeninput/">Token Field</a>, pluginu napisanego w jquery, który umożliwia wygodne dodawanie rekordów dla assocjacji wiele i wiele do wielu. W poniższym artykule chciałbym pokazać w jaki sposób dodać nowe rekordy za pomocą ajax-a. Przed przeczytaniem tutoriala, polecam obejrzenie railscastu (trwa tylko 10 minut)</p>
<p>Aplikację stworzoną w poniższym artykule można ściągnąć z <a href="https://github.com/slawosz/Add-resource-with-ajax-and-facebox-tutorial">githuba</a> lub zobaczyć jak działa na <a href="http://add-new-resource-with-ajax.heroku.com/">heroku</a>. Do jej stworzenia wykorzystałem aplikację stworzoną w railscaście 258.</p>
<p>Aby dodać nowego autora możemy przejść pod adres <code>/author/new</code>, ale gdy dodajemy książkę i chcemy przypisać do niej jeszcze nie istniejącego autora, lepiej będzie wyświetlić formę dodawania autora używając ajax’a. Do wyświetlenia formy użyjemy <a href="https://github.com/defunkt/facebox">faceboxa</a>, napisanego w jquery przez Chris’a Wanstrath’a.</p>
<h3>Zaczynamy &#8211; instalacja faceboxa!</h3>
<p>Ściągnijmy faceboxa z githuba, rozpakujmy i umieśćmy odpowiednio pliki w naszej aplikacji: <code>facebox.css w public/stylesheets, facebox.js w public/javascripts,  loading.gif i closelabel.png w public/images</code>.</p>
<p>Teraz wpiszemy ścieżki do obrazków faceboxa w pliku public/javascripts/facebox.js:</p>
<pre class="sh_javascript">loadingImage: '/images/loading.gif',
closeImage: '/images/closelabel.png'</pre>
<p>oraz umieścimy arkusz css i plik z kodem javascript w pliku layoutu <code>app/views/layouts/application.html.erb</code>:</p>
<pre  class="sh_ruby">&lt;%= stylesheet_link_tag "application", "token-input-facebook","facebox" %&gt;
&lt;%= javascript_include_tag :defaults, "jquery.tokeninput","facebox" %&gt;</pre>
<h3>Formularz na faceboxie &#8211; jakie to proste <img src='http://rubysfera.pl/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </h3>
<p>Teraz przejdźmy do wyświetlenia formularza dodawania nowego autora za pomocą faceboxa.<br />
Musimy dodać odpowiedni link w pliku <code>app/views/books/_form.html.erb</code>:</p>
<pre class="sh_ruby">&lt;%= f.label :author_tokens, "Authors" %&gt;
&lt;%= link_to 'Add new author', new_author_path, :remote =&gt; true %&gt;</pre>
<p>Powyższy link posiada opcję <code>:remote</code>, która spowoduje wywołanie akcji <code>new</code> za pomocą ajaxa. Aby to zadziałało, musimy lekko zmodyfikować akcję w kontrollerze <code>AuthorsController</code>.</p>
<p>Osługa naszego żądania js w kontrolerze dzieki Railsom jest bardzo prosta. Wystarczy dodać nowy widok <code>app/views/authors/new.js.erb</code>. Po kliknięciu linku, metoda rozpozna, że żądanie jest w formacie <code>js</code> i wyświetli widok formatu <code>js</code>. Teraz dodajmy do widok kod który wyrenderuje nową akcję za pomocą faceboxa:</p>
<pre class="sh_javascript">$.facebox('&lt;%= escape_javascript(render :template =&gt; 'books/new.html') %&gt;');</pre>
<p>Powyższy kod wygeneruje formę dodawania nowego autora na faceboxie (<code>app/views/books/new.html.erb</code> ). Podając argument dla opcji <code>:template</code> musimy wskazać html-owy widok. Tworząc aplikację Rails z rozbudowaną obsługą Ajaxa znacznie częściej używany partiali, jednak nasze zadanie można wykonać bez modyfikacji istniejącego kodu używając opcji <code>template</code>.</p>
<p>Jeśli chcecie się dowiedzie więcej na temat używania faceboxa, w pliku <code>public/javascripts/facebox.js</code> są bardzo dobrze opisane wszystkie możliwości użycia.</p>
<h3>Dodawanie autora &#8211; wreszcie coś działa!</h3>
<p>Teraz chcemy wysłać nasz formularz i stworzyć nowego autora. Normalnie użylibyśmy opcji</p>
<pre  class="sh_ruby">:remote =&gt; true</pre>
<p>w definicji formularza, ale w naszym przypadku chcemy użyć ajax’a jedynie na faceboxie. Aby uczynić tylko formularz na faceboxie ajaxowym, dodajmy poniższą linijkę w pliku <code>app/views/books/new.js.erb</code>:</p>
<pre class="sh_javascript">$('#facebox form').data('remote','true');</pre>
<p>Kod doda htmlowy atrybut <code>data-remote=’true’</code> w znaczniku <code>form</code>, dzięki czemu plik <code>public/javascript/rails.js</code> przechwyci wysłanie formularza i wykona żądanie ajaxowe. Formularz jest wysyłany do akcji <code>create</code> w <code>AuthorsController</code> i potrzebuje templata w formacie <code>js</code>. Zatem tworzymy plik <code>app/views/authors/create.js.erb</code>, za pomocą którego zamykamy faceboxa:</p>
<pre  class="sh_javascript">$(document).trigger('close.facebox');</pre>
<p>Ponieważ akcja create inaczej zachowuje się przy żądaniu <code>html</code> i <code>js</code>, musimy użyć bloku <code>respond_to</code>. W przypadku żądania <code>html</code> przekierowujemy użytkownika na stronę autora, a przy żądaniu <code>js</code> wyświetlamy opisany wyżej widok <code>js</code>.</p>
<pre  class="sh_ruby">def create
  @author = Author.new(params[:author])
  if @author.save
    respond_to do |format|
      format.html { redirect_to @author, :notice =&gt; "Successfully created author." }
      format.js
    end
  else
    render :action =&gt; 'new'
  end
end</pre>
<h3>Gotowe? Jeszcze parę poprawek&#8230;</h3>
<p>Osiągnęliśmy nasz cel, ale musimy jeszcze wprowadzić parę usprawnień. Kiedy obiekt <code>@author</code> nie może być zapisany, powinniśmy wyświetlić formularz dodawania ponownie na faceboxie. W <code>app/models/author.rb</code> dodajmy walidację:</p>
<pre class="sh_ruby">validates :name, :presence =&gt; true</pre>
<p>Od teraz nie możemy dodać autora bez nazwy. Kiedy spróbujemy, dostaniemy błąd walidacji, który chcemy wyświetlić na faceboxie.</p>
<p>Na początku zmieńmy akcję create aby użyć widoku js,  wprzypadku gdy nie uda nam się zapisać rekordu:</p>
<pre class="sh_ruby">def create
  @author = Author.new(params[:author])
  if @author.save
    respond_to do |format|
      format.html { redirect_to @author, :notice =&gt; "Successfully created author." }
      format.js
    end
  else
    respond_to do |format|
      format.html { render :action =&gt; 'new' }
      format.js
    end
  end
end</pre>
<p>I zmodyfikujmy plik <code>app/views/books/create.js.erb</code> aby wyświetlić formularz z błędami na facebox’ie przy nie udanym zapisie obiektu <code>@author</code>:</p>
<pre  class="sh_ruby">&lt;% if @author.save %&gt;
  $(document).trigger('close.facebox')
&lt;% else %&gt;
  $('#facebox .content').html('&lt;%= escape_javascript(render :template =&gt; 'authors/new') %&gt;')
  $('#facebox form').data('remote','true');
&lt;% end %&gt;</pre>
<p>Wreszcie mamy działające ajaxowe dodawanie autorów, wprowadzając minimalne zmiany w kodzie.</p>
<h3>Jeszcze jedno malutkie usprawnienie.</h3>
<p>Wprowadźmy jeszcze jedną małą zmianę &#8211; usuńmy link ‘Back to list’ z formy na faceboxie. Na faceboxie ten link jest kompletnie bezużyteczny. Zrobimy to za pomocą poniższej linijki jQuery:</p>
<pre   class="sh_javascript">$('#facebox .content p:last').remove();</pre>
<p>Po prostu usuwamy ostatni tag w formularzu generowanym na faceboxie.</p>
<p>Powyższy kod dodajemy na końcu pliku <code>app/views/authors/new.js.erb</code> i na końcu sekcji else w <code>app/views/authors/create.js.erb</code>. To już naprawdę koniec!</p>
<p>Na <a href="http://add-new-resource-with-ajax.heroku.com/">heroku</a> możesz zobaczyc demo aplikacji, a jej kod na <a href="https://github.com/slawosz/Add-resource-with-ajax-and-facebox-tutorial">githubie</a>.<br />
Wszystkie zmiany znajdują się w commicie<a href="https://github.com/slawosz/Add-resource-with-ajax-and-facebox-tutorial/commit/cf13adacdff595059dc6eba0fcb33c0204ad6714"> cf13adacdff595059dc6eba0fcb33c0204ad6714</a></p>
<p>Jeśli chcesz wiedzieć więcej o działaniu javascripta w Rails 3, odwiedź poniższe linki:<br />
<a href="http://rubysfera.pl/2010/11/javascript-w-rails-3/">http://rubysfera.pl/2010/11/javascript-w-rails-3/</a><br />
<a href="http://www.simonecarletti.com/blog/2010/06/unobtrusive-javascript-in-rails-3/">http://www.simonecarletti.com/blog/2010/06/unobtrusive-javascript-in-rails-3/</a><br />
<a href="http://www.alfajango.com/blog/rails-jquery-ujs-now-interactive/">http://www.alfajango.com/blog/rails-jquery-ujs-now-interactive/</a></p>
]]></content:encoded>
			<wfw:commentRss>http://rubysfera.pl/2011/05/ajaxowe-dodawanie-nowego-rekordu/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>TDD z użyciem Test::Unit</title>
		<link>http://rubysfera.pl/2011/04/tdd-z-uzyciem-testunit/</link>
		<comments>http://rubysfera.pl/2011/04/tdd-z-uzyciem-testunit/#comments</comments>
		<pubDate>Tue, 19 Apr 2011 07:14:37 +0000</pubDate>
		<dc:creator>tjeden</dc:creator>
				<category><![CDATA[Tutoriale]]></category>

		<guid isPermaLink="false">http://rubysfera.pl/?p=894</guid>
		<description><![CDATA[Na przykładzie czystego Rubiego (bez Railsów) pokazujemy jak zaimplementować średnią zgodnie z <strong>Test-driven development</strong> przy użyciu starego dobrego <strong>Test/Unit</strong>.]]></description>
			<content:encoded><![CDATA[<p><a href="http://rubysfera.pl/2011/04/tdd-z-uzyciem-testunit/tdd/" rel="attachment wp-att-896"><img src="http://rubysfera.pl/wp-content/uploads/2011/04/tdd.png" alt="" title="tdd" width="300" height="200" class="alignright size-full wp-image-896" /></a>
<p>Jakiś czas temu przetoczyło się w blogosferze <a href="http://www.rubyinside.com/dhh-offended-by-rspec-debate-4610.html">dyskusja o wyższości test/unit nad rspekiem</a>. Uważam, że to tak naprawdę kwestia gustu, ale ponieważ dużo osób jest zmęczonych rspekiem, dziś pora na pokazanie przykładowej sesji <a href="http://en.wikipedia.org/wiki/Test-driven_development">TDD</a> właśnie w oparciu o <a href="http://en.wikibooks.org/wiki/Ruby_Programming/Unit_testing">test/unit</a>.</p>
<h3>Teoria TDD w wielkim skrócie</h3>
<p>Dla tych którzy nie wiedzą na czym polega Test Driven Development (a są tacy), przypominam, że to proces produkcji oprogramowania, który składa się z trzech etapów:</p>
<ol>
<li>Napisz test, który sprawdza funkcję, którą piszesz. Test powinien zakończyć się błędem.</li>
<li>Napisz kod, który sprawi, że test zacznie działać.</li>
<li>Zrefaktoryzuj otrzymany kod, posiłkując się przygotowanym testem.</p>
</ol>
<p>Po wykonaniu takiej iteracji otrzymuje sensowny, otestowany kod i możemy zająć się pisaniem kolejnej funkcji.</p>
<h3>Praktyka testowania</h3>
<p>W tym przykładzie napiszemy metodę <code>average</code> dla klasy <code>Array</code>. Zacznijmy od przygotowania testu, który sprawdzi dwa proste przypadki.</p>
<p>Przygotujemy dwa pliki: <code>lib/average.rb</code> &#8211; który będzie zawierał kod (na razie pusty) oraz <code>test/test_average.rb</code>, w którym umieścimy nasz test:</p>
<pre class="sh_ruby">
require 'lib/average'
require 'test/unit'

class TestAverage < Test::Unit::TestCase

  def test_simple
    assert_equal '4,5', [4,5].average
    assert_equal '3', [2,2,3,5].average
  end

end
</pre>
<p>Na potrzeby testu ładujemy plik z naszym kodem i bibliotekę <code>test/unit</code>. Klasa testowa musi dziedziczyć po <code>Test::Unit::TestCase</code>. Metoda testowa powinna zaczynać się od słowa <code>test</code>, dzięki czemu zostanie ona wywołana. Wszystkie metody bez tego przedrostka traktowane są jako pomocnicze i nie są automatycznie wywoływane przy uruchomienia. Tak przygotowany test uruchamiamy poleceniem:</p>
<pre class="sh_ruby">
ruby test/test_average.rb
</pre>
<p>Jeśli dobrze napisaliśmy test, to powinniśmy otrzymać błąd. Jeśli test jest spełniony bez pisania kodu, to znaczy, że albo gdzieś już mamy odpowiednie metody, albo (co bardziej prawdopodobne), test został napisany błędnie.</p>
<pre>
Loaded suite test/test_average
Started
E
Finished in 0.000278 seconds.

  1) Error:
test_simple(TestAverage):
NoMethodError: undefined method `average' for [4, 5]:Array
    test/test_average.rb:5:in `test_simple'

1 tests, 0 assertions, 0 failures, 1 errors
</pre>
<p>Test klarownie mówi nam, że nie posiadamy metody <code>average</code> w klasie <code>Array</code>. Aby ją dodać należy otworzyć klasę <code>Array</code>. Istnieją bardziej eleganckie sposoby jej dodania, my wykorzystamy najbardziej prymitywny z nich, to jest artykuł o TDD i kropka. W pliku <code>lib/average.rb</code> zdefiniujmy naszą metodę.</p>
<pre class="sh_ruby">
class Array

  def average
  end

end
</pre>
<p>Ponownie odpalamy test i widzimy, że nasza metoda zwraca niewłaściwy wynik:</p>
<pre>
Loaded suite test/test_average
Started
F
Finished in 0.024466 seconds.

  1) Failure:
test_simple(TestAverage) [test/test_average.rb:6]:
<"4,5"> expected but was
<nil>.

1 tests, 1 assertions, 1 failures, 0 errors
</pre>
<p>Pora zatem zaimplementować średnią w najbardziej prosty i prymitywny sposób:</p>
<pre class="sh_ruby">
class Array

  def average
    sum = 0
    count = 0
    self.each do |element|
      sum += element
      count += 1
    end
    sum/count
  end

end
</pre>
<pre>
Loaded suite test/test_average
Started
F
Finished in 0.004176 seconds.

1) Failure:
test_simple(TestAverage) [test/test_average.rb:7]:
<"4,5"> expected but was
<4>.
</pre>
<p>Prawie zadziałało. Niestety ponieważ <code>sum</code> jest liczbą całkowitą, otrzymany wynik, też jest całkowity. Pora to naprawić.</p>
<pre class="sh_ruby">
class Array

  def average
    sum = 0
    count = 0
    self.each do |element|
      sum += element
      count += 1
    end
    sum.to_f/count
  end

end
</pre>
<pre>
Loaded suite test/test_average
Started
F
Finished in 0.004232 seconds.

1) Failure:
test_simple(TestAverage) [test/test_average.rb:7]:
<"4,5"> expected but was
<4.5>.

1 tests, 1 assertions, 1 failures, 0 errors
</pre>
<p>Ponieważ jesteśmy gapy, w teście podaliśmy, że wynik ma być łańcuchem znaków, a przecież również powinien być liczbą. Poprawiamy test, usuwając cudzysłowy.</p>
<pre class="sh_ruby">
require 'lib/average'
require 'test/unit'

class TestAverage < Test::Unit::TestCase

  def test_simple
    assert_equal 4.5, [4,5].average
    assert_equal 3, [2,2,3,5].average
  end

end
</pre>
<pre>
Loaded suite test/test_average
Started
.
Finished in 0.000239 seconds.

1 tests, 2 assertions, 0 failures, 0 errors
</pre>
<p>Hurra! Udało się, teraz warto zastanowić się nad ciekawszym przypadkiem: np. co się stanie, gdy tablica będzie pusta. W takim przypadku wynik powinien być nilem, dodajemy zatem drugi test.</p>
<pre class="sh_ruby">
require 'lib/average'
require 'test/unit'

class TestAverage < Test::Unit::TestCase

  def test_simple
    assert_equal 4.5, [4,5].average
    assert_equal 3, [2,2,3,5].average
  end

  def test_empty_array
    assert_nil [].average
  end

end
</pre>
<pre>
Loaded suite test/test_average
Started
F.
Finished in 0.00441 seconds.

1) Failure:
test_empty_array(TestAverage) [test/test_average.rb:12]:
<nil> expected but was
<NaN>.

2 tests, 3 assertions, 1 failures, 0 errors
</pre>
<p>Test nam przypomniał o wierszyku: pamiętaj cholero, nie dziel przez zero. Musimy obsłużyć taki przypadek.</p>
<pre class="sh_ruby">
class Array

  def average
    sum = 0
    count = 0
    each do |element|
      sum += element
      count += 1
    end
    sum.to_f/count if count != 0
  end

end
</pre>
<pre>
Loaded suite test/test_average
Started
..
Finished in 0.000383 seconds.

2 tests, 3 assertions, 0 failures, 0 errors
</pre>
<p>Jest dobrze; mamy test, mamy działający kod, to jest ten moment, w którym należy na kod spojrzeć krytycznie. Nie musimy ręcznie liczyć elementów tablicy, możemy skorzystać z metody <code>size</code>.</p>
<pre class="sh_ruby">
class Array

  def average
    sum = 0
    each do |element|
      sum += element
    end
    sum.to_f/size unless size == 0
  end

end
</pre>
<p>O dwie linijki prościej. Sprawdźmy, czy to działa:</p>
<pre>
Loaded suite test/test_average
Started
..
Finished in 0.000383 seconds.

2 tests, 3 assertions, 0 failures, 0 errors
</pre>
<p>Czy można to jeszcze skrócić? Przy pomocy <code>inject</code> tak.</p>
<pre class="sh_ruby">
class Array

  def average
    inject{ |sum, element| sum + element }.to_f / size unless size == 0
  end

end
</pre>
<pre>
Loaded suite test/test_average
Started
..
Finished in 0.000383 seconds.

2 tests, 3 assertions, 0 failures, 0 errors
</pre>
<p>Zadziałało, może jeszcze bardziej?</p>
<pre class="sh_ruby">
class Array

  def average
    inject(:+).to_f / size unless size == 0
  end

end
</pre>
<p><code>Inject</code> otrzymał symbol operacji, którą ma przeprowadzić na wszystkich elementach tablicy. Ponieważ operacją tą jest dodawanie, to należy operator dodwania <code>+</code> poprzedzić znakiem symbolu <code>:</code>. Gdyby metodą, którą chcemy wykonać było <code>foo</code>, to kod musiałby wyglądać tak: <code>inject(:foo)</code>. Sprawdźmy, czy ta przypominającą emotikonkę konstrukcja zadziała:</p>
<pre>
Loaded suite test/test_average
Started
..
Finished in 0.000312 seconds.

2 tests, 3 assertions, 0 failures, 0 errors
</pre>
<p>Tak oto przeszliśmy przez trzy fazy TDD. Napisaliśmy test; napisaliśmy kod, który przechodzi ten test; a potem poprawiliśmy ten kod, żeby wyglądał lepiej. I wcale nie było to takie trudne.</p>
]]></content:encoded>
			<wfw:commentRss>http://rubysfera.pl/2011/04/tdd-z-uzyciem-testunit/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Javascript w Rails 3</title>
		<link>http://rubysfera.pl/2010/11/javascript-w-rails-3/</link>
		<comments>http://rubysfera.pl/2010/11/javascript-w-rails-3/#comments</comments>
		<pubDate>Mon, 22 Nov 2010 23:52:16 +0000</pubDate>
		<dc:creator>Czak</dc:creator>
				<category><![CDATA[Tutoriale]]></category>

		<guid isPermaLink="false">http://rubysfera.pl/?p=661</guid>
		<description><![CDATA[<strong>Unobtrusive Javascript</strong>, <strong>AJAX</strong>, <strong>Ruby on Rails</strong>, a wszystko okraszone szczyptą <code>respond_with</code>. Feeria słów kluczowych Web 2.0 na chłodne zimowe wieczory.]]></description>
			<content:encoded><![CDATA[<p><img src="http://rubysfera.pl/wp-content/uploads/2010/11/srsly.jpg" alt="" title="srsly" width="300" height="200" class="alignright size-full wp-image-680" />Jako technologii server-side Railsów specjalnie zachwalać nie trzeba. Szczególnie wśród czytelników Rubysfery. Aktualny trend w webdevelopmencie przenosi jednak coraz większy ciężar na front-end. Budujemy coraz bardziej wymyślne <abbr title="Graphical User Interface">GUI</abbr> i piszemy coraz więcej Javaskryptu. <a href="http://en.wikipedia.org/wiki/Ajax_(programming)">AJAX</a> przestał być modnym słowem kluczowym, a stał się standardem. Aby uprościć budowę aplikacji opartych na Ajaksie, w Railsach od dawna istniały helpery <code>link_to_remote</code> czy <code>remote_form_for</code>, a bliska integracja frameworku z biblioteką <a href="http://www.prototypejs.org/">Prototype.js</a> sprawiała, że próg wejścia w ten świat był wyjątkowo niski.</p>
<p>Sporo jednak się zmieniło. Rozwiązania oparte o <code>onclick</code> czy generowanie wymyślnych formularzy są wyjątkowo <em>passé</em>, a na domiar złego faworytem wielu webdeveloperów stało się w ostatnich latach <a href="http://jquery.com/">jQuery</a>. Team Rails zdawał się te drobiazgi mieć w głębokim poważaniu. Aż nadeszła wersja 3.</p>
<h3>Wreszcie</h3>
<p>Najważniejszą nowością w tym temacie jest uniezależnienie Railsów od Prototype.js. Jeśli chcemy korzystać z jQuery, nic nie stoi nam na przeszkodzie i wcale nie musimy rezygnować z railsowych helperów. Co więcej, odpowiedni moduł <a href="https://github.com/rails/jquery-ujs">rails.js w wersji dla jQuery</a> jest rozwijany przez Rails Team równolegle z <a href="https://github.com/rails/prototype-ujs">wersją dla Prototype</a>. Użytkownicy innych bibliotek znajdą również &#8211; już nieoficjalne acz w pełni sprawne &#8211; wersje dla <a href="https://github.com/kevinvaldek/mootools-ujs">MooTools</a>, <a href="https://github.com/erwanb/ext-ujs">Ext.js</a> czy <a href="https://github.com/epotocko/yui3-ujs">YUI</a>.</p>
<p>Warto też zwrócić uwagę na gem <a href="https://github.com/indirect/jquery-rails">jquery-rails</a>, który upraszcza migrację Prototype &rarr; jQuery do wywołania generatora:</p>
<pre>
rails generate jquery:install
</pre>
<p>Komenda usunie pozostałości po Prototypie, pobierze świeże jQuery i odpowiedni rails.js i zadba by <code>javascript_include_tag :defaults</code> właśnie te dwa pliki wczytywało.</p>
<h3>Jak to działa?</h3>
<p>Po pierwsze, zapominamy o <code>link_to_remote</code> i jego pobratymcach. W 3.x mamy tylko opcję <code>:remote => true</code>. Dodajemy ją do <code>link_to</code>, <code>button_to</code> lub <code>form_for</code> i tym prostym sposobem otrzymujemy ajaksowy &#8211; miast zwykłego &#8211; link, przycisk lub formularz.</p>
<p>Powyższa opcja zdaje się robić bardzo niewiele. Do wygenerowanego linku lub formularza dodaje jedynie atrybut <code>data-remote="true"</code>. Co to za cudo i gdzie podział się mój <code>onclick</code>?!</p>
<p>Atrybuty <code>data-*</code> to wprowadzony w HTML5 <a href="http://dev.w3.org/html5/spec/Overview.html#embedding-custom-non-visible-data-with-the-data-attributes">standard</a> wiązania dowolnych danych z elementami HTML. Całkowicie poprawny (w rozumieniu poprawności HTML5) jest przykładowy element:</p>
<pre>
&lt;li data-villain="Kapitan Wyspa"&gt;Wilq&lt;/li&gt;
</pre>
<p>&#8230;w którym to przebiegle powiązałem superbohatera z jego adwersarzem. Railsy zaadoptowały ten mechanizm m.in. do oznaczenia linków lub formularzy jako ajaksowe (remote).</p>
<p>Nie byłoby jednak magii Ajaksu bez wspomnianego wcześniej pliku rails.js. W nim zaimplementowano mechanizmy wysyłania zapytań i submitowania formularzy w tle. Tutaj odpowiednie handlery podpinane są do linków i formularzy z <code>data-remote="true"</code>. I każda z rozwijanych oddzielnie wersji robi dokładnie to samo we własnym dialekcie Javaskryptu.</p>
<h3><code>remote</code> to nie wszystko</h3>
<p>Oprócz dodania <code>:remote</code>, face-lifting przeszły opcje <code>:method</code> i <code>:confirm</code>. Najbardziej wypasiony <code>link_to</code> z potwierdzeniem i usuwaniem przez Ajax:</p>
<pre class="sh_ruby">
link_to "Usuń", @product, :method  => :delete,
                          :confirm => "Czy aby na pewno?",
                          :remote  => true
</pre>
<p>generuje w Rails 3 całkiem zgrabne:</p>
<pre class="sh_html">
&lt;a href="/products/7" data-confirm="Czy aby na pewno?" data-method="delete" &crarr;
data-remote="true" rel="nofollow"&gt;Usuń&lt;/a&gt;
</pre>
<p>Analogicznie jak wcześniej, cała logika wywołania <code>confirm("Czy aby na pewno?");</code> i ustawienia metody zapytania znajduje się w pliku rails.js.</p>
<h3>I co dalej?</h3>
<p>A dalej jest oczywiście kontroler. I akcja, która musi dany request &#8211; ajaksowy czy nie &#8211; obsłużyć. Tu warto wspomnieć o jeszcze jednej perełce w Rails 3. Dla mnie osobiście to odkrycie stulecia. Para <code>respond_to</code> i <code>respond_with</code> pozwoli skrócić kod każdego Twojego kontrolera o połowę. Nie ściemniam. Weźmy dość standardowy przykład z Rails 2.x:</p>
<pre class="sh_ruby">
def index
  @users = User.all
  respond_to do |format|
    format.html
    format.xml { render &#58;xml => @users }
    format.json { render :json => @users }
  end
end
</pre>
<p>Jedna akcja renderuje standardowy widok HTML lub, na życzenie, zwraca reprezentację JSON lub XML. Żadna fanaberia. W Rails 3 może to wyglądać tak:</p>
<pre class="sh_ruby">
respond_to :html, &#58;xml, :json

def index
  @users = User.all
  respond_with @users
end
</pre>
<p><code>respond_to</code> służy do zadeklarowania akceptowanych formatów, a <code>respond_with</code> na podstawie przekazanego obiektu i żądanego formatu wykona odpowiednią operację. A jak się to ma do Javaskryptu? Weźmy inny przykład:</p>
<pre class="sh_ruby">
respond_to :html, :js

def create
  @article = Article.create(params[:article])
  respond_with @article
end
</pre>
<p>Długo by wymieniać ile magii znajduje się w jednej linijce <code>respond_with</code>. Zaczynając od wariantu <code>:html</code>, metoda ta inaczej zachowa się jeśli <code>@article.valid?</code> (przekieruje na <code>article_path(@article)</code>), a inaczej jeśli nie (wyrenderuje akcję <code>new</code>, a jakże). Jeśli zapytanie przyszło z Javascriptu, choćby z formularza z ustawionym <code>:remote => true</code>, akcja wyrenderuje natomiast <code>create.js.erb</code>, w którym mamy dostęp do @article i możemy w UI natychmiast odzwierciedlić zmianę.</p>
<p>Dziękuję, dobranoc. Kwiaty można przysyłać pocztą na adres redakcji <img src='http://rubysfera.pl/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />  Więcej info o <code>respond_with</code> w <a href="http://ryandaigle.com/articles/2009/8/6/what-s-new-in-edge-rails-cleaner-restful-controllers-w-respond_with">artykule Ryana Daigle</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://rubysfera.pl/2010/11/javascript-w-rails-3/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Tworzymy stronę &#8222;Under construction&#8221;</title>
		<link>http://rubysfera.pl/2010/11/tworzymy-strone-under-construction/</link>
		<comments>http://rubysfera.pl/2010/11/tworzymy-strone-under-construction/#comments</comments>
		<pubDate>Mon, 08 Nov 2010 09:53:11 +0000</pubDate>
		<dc:creator>tjeden</dc:creator>
				<category><![CDATA[Tutoriale]]></category>

		<guid isPermaLink="false">http://rubysfera.pl/?p=574</guid>
		<description><![CDATA[Przepis na przygotowanie strony informującej o trwającej aktulizacji przy pomocy <strong>nginxa</strong> i <strong>capistrano</strong>.]]></description>
			<content:encoded><![CDATA[<p><a href="http://rubysfera.pl/2010/11/tworzymy-strone-under-construction/under_contruction/" rel="attachment wp-att-579"><img src="http://rubysfera.pl/wp-content/uploads/2010/11/under_contruction.jpg" alt="" title="under_contruction" width="300" height="200" class="alignright size-full wp-image-579" /></a></p>
<p>Pamiętacie animowane gify z początku Internetu? Kilkanaście lat temu najważniejszą rzeczą w procesie tworzenia strony było wrzucenie na serwer świecącego animowanego gifa, obowiązkowo z widokiem placu budowy i wielkim <strong>under construction</strong>. Potem wystarczyło już nigdy nie zaglądać na ten serwer i mieliśmy piękną stronę wiecznie w budowie (jak <a href="http://pl.wikipedia.org/wiki/Świątynia_Opatrzności_Bożej_w_Warszawie">Świątynia Opatrzności Bożej</a>).</p>
<p>W dobie blogów w 15 minut i <a href="http://www.wykop.pl/link/229300/silnik-ala-demotywatory-pl-za-50zl/">silinków ala demotywatory za 50zł</a>, o wrzuceniu tekstu &#8222;strona w budowie&#8221; nikt już nie myśli. Czasem jednak chcielibyśmy mieć możliwość wygodnego poinformowania użytkowników, że robimy migrację lub właśnie coś zmieniamy. Dziś szybki przepis jak to zrobić.</p>
<p>Potrzebne nam będą:</p>
<ul>
<li><strong>Nginx z Passengerem</strong> jako serwer http.</li>
<li><strong>Capistrano</strong> jako narzędzie do deploymentu.</li>
<li>Railsowa aplikacja.</li>
<li>Strona z gifem <strong>under construction</strong>, może być też jakiś stylowy licznik, że wracamy za 7 dni.</li>
<li>Butelka piwa &#8211; zawsze się przyda.</li>
</ul>
<p>Nasz plik z gifem nazwijmy <code>maintenance_file.html</code>, umieśćmy w katalogu <code>public</code> i dodajmy go do repozytorium.</p>
<pre>public/maintance_file.html</pre>
<p>Na serwerze znajdźmy plik konfiguracyjny nginxa. Prawdopodobnie znajduje się w katalogu <code>/opt/nginx/conf/nginx.conf</code>. Wewnątrz dyrektywy <code>server</code> dodajmy następujący wpis:</p>
<pre>if (-f $document_root/maintenance.html) {
  rewrite ^(.*)$ /maintenance.html break;
}
</pre>
<p>Cały dyrektywa <code>server</code> powinien wyglądać wtedy podobnie do poniższego.</p>
<pre>
server {
    server_name www.foo.com;
    listen 80;
    root /webapps/foo/public;
    passenger_enabled on;

    if (-f $document_root/maintenance.html) {
        rewrite ^(.*)$ /maintenance.html break;
    }
}
</pre>
<p>Jeśli w katalogu public jest plik <code>maintance.html</code> to wtedy o cokolwiek nie poprosimy, to dostaniemy ten plik. Dlatego plik w naszym repozytorium nazywa się inaczej (<code>maintence_file.html</code>). Zostało teraz tylko tak przygotować capistrano, by przed restartem w naszym katalogu public pojawiał się plik <code>maintance</code> i znikał po jego zakończeniu.</p>
<pre>
before 'deploy:restart', 'deploy:disable_site'
after 'deploy:restart', 'deploy:enable_site'

namespace :deploy do
  desc "Enables site"
  task :enable_site, :roles => :app do
    run "rm -f #{current_path}/public/maintenance.html"
  end

  desc "Disables site"
  task :disable_site, :roles => :app do
    run "ln -nfs #{current_path}/public/assets/maintenance.html /
     #{current_path}maintenance_file.html"
  end
end
</pre>
<p>I to wszystko. Osobną kwestią, pozostaje, w którym momencie chcemy pokazywać użytkownikowi informację o niedostępności strony, ale cały mechanizm pozostaje bez zmian. Użytkownicy Appacha, mogą zastosować <a href="http://www.techiecorner.com/97/redirect-to-maintenance-page-during-upgrade-using-htaccess/">podobny mechanizm</a>.</p>
<p>Byłbym zapomniał. Jak wszystko zadziała ładnie, to możemy wypić piwo.</a></p>
]]></content:encoded>
			<wfw:commentRss>http://rubysfera.pl/2010/11/tworzymy-strone-under-construction/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Aplikacja działająca na dwóch serwerach</title>
		<link>http://rubysfera.pl/2010/08/aplikacja-dzialajaca-na-dwoch-serwerach/</link>
		<comments>http://rubysfera.pl/2010/08/aplikacja-dzialajaca-na-dwoch-serwerach/#comments</comments>
		<pubDate>Mon, 30 Aug 2010 05:30:03 +0000</pubDate>
		<dc:creator>tjeden</dc:creator>
				<category><![CDATA[Tutoriale]]></category>

		<guid isPermaLink="false">http://rubysfera.pl/?p=281</guid>
		<description><![CDATA[Obszerny przewodnik o tym jak skonfigurować <strong>nginxa</strong>, <strong>capistrano</strong> i <strong>bazę danych</strong>, tak by aplikacja działała na dwóch lub więcej serwerach.]]></description>
			<content:encoded><![CDATA[<p><a href="http://rubysfera.pl/2010/08/aplikacja-dzialajaca-na-dwoch-serwerach/double_servers/" rel="attachment wp-att-329"><img src="http://rubysfera.pl/wp-content/uploads/2010/08/double_servers.jpg" alt="" title="double_servers" width="300" height="200" class="alignright size-full wp-image-329" /></a><br />
Zazwyczaj aplikacje, które piszemy, nie mają użytkowników i zbyt wiele ruchu. Czasem coś jednak pójdzie nie tak, pojawią się użytkownicy i jeden serwer na którym nasza aplikacja działa, przestaje wystarczać.  Poniższy przewodnik opowiada jak skonfigurować dwa (lub więcej) serwerów do obsługiwania naszej aplikacji. Może się on przydać, również osobom, chcącym połączyć się z bazą danych umieszczoną na innym serwerze niż aplikacja.</p>
<h3>Założenia</h3>
<ul>
<li>Zakładam, że korzystasz z <a href="http://www.capify.org/index.php/Getting_Started">Capistrano</a>. Jeśli nie, to prawdopodobnie powinieneś.</li>
<li>Posiadasz Railsową aplikację zdeployowaną na jednym serwerze produkcyjnym.</li>
<li>Korzystasz z <a href="http://nginx.org">Nginxa</a>, jak serwera WWW z zainstalowanym <a href="http://www.modrails.com/install.html">Phusion Passengerem</a>. (Konfiguracja dla <a href="http://www.apache.org/">Apacha</a> będzie podobna)</li>
<li>Jako baza danych wykorzystywany jest MySQL. Instrukcje udostępniania połączenia dla innych rodzajów baz danych mogą odbiegać od tego co jest opisane w tym przewodniku.</li>
<li>Serwer w tym przypadku to Debian, ale na wszystkich systemach *nixowych powinno to wyglądać podobnie.</li>
</ul>
<h3>Schemat konfiguracji</h3>
<p><strong>Master serwer</strong> – główny serwer, który będzie przyjmował żądania i je rozdzielał (część przekaże na inne serwery, część obsłuży sam). Na nim znajduje się baza i procesy chodzące w tle (backgroundrb, delayed_job, sphinx itp&#8230;)<br />
<strong>Slave serwer</strong> – drugi serwer, służący wyłącznie jako serwer aplikacji, łączy się z bazą znajdującą się na master serwerze.<br />
<div id="attachment_295" class="wp-caption aligncenter" style="width: 350px"><a href="http://rubysfera.pl/2010/08/aplikacja-dzialajaca-na-dwoch-serwerach/2-serwery-schemat/" rel="attachment wp-att-295"><img src="http://rubysfera.pl/wp-content/uploads/2010/08/2-serwery-schemat.png" alt="" title="2 serwery schemat" width="340" height="531" class="size-full wp-image-295" /></a><p class="wp-caption-text">Schemat konfiguracji</p></div></p>
<p>Taka konfiguracja umożliwia dodanie więcej niż jednego równoległego slave serwera. W pewnym momencie warto również pomyśleć o przeniesieniu bazy na osobny serwer.</p>
<h3>Ustawienia capistrano</h3>
<p>Capistrano oparte jest o system ról, z których skorzystamy. Różnym serwerom możemy przypisać różne role, a poszczególnym rolom różne zadania. Dzięki temu możemy sprawić, by zadania związane z bazą i procesy chodzące w tle pracowały tylko na maszynie z rolą: <code>:db</code/>. Jeśli mamy już skonfigurowane Capistrano, to powinniśmy do roli <code>:app</code> przypisać adres ip drugiego serwera.</p>
<pre class="sh_ruby">
role :app, "master_serwer_ip", "slave_serwer_ip"
role :db, "master_serwer_ip"
</pre>
<p>Zadania, które powinny być wykonywane wyłącznie na serwerze głównym należy oznaczyć <code>:roles => :db</code>.</p>
<pre class="sh_ruby">
task :restart, :roles => :db do
  run "cd #{release_path} &#038;&#038; RAILS_ENV=production rake ts:rebuild &#038;"
end</pre>
<h3>Tworzenie usera na slave</h3>
<p>Na slave serwerze należy stworzyć użytkownika z takim samym hasłem i nazwą jak na serwerze master. Załóżmy, że posiadamy użytkownika <code>capistrano</code> z hasłem <code>some_password</code>. Logujemy się jako root na slave serwer:</p>
<pre>
useradd capistrano -p some_password
cd /home
mkdir capistrano
chown -R capistrano capistrano
chrgp -R capistrano capistrano</pre>
<p>I mamy stworzonego użytkownika.</p>
<h3>Przygotowanie deploya</h3>
<p>Należy na serwerze slave stworzyć katalog do którego będziemy robić deploye. Najwygodniej nam będzie, jeśli struktura katalogów będzie identyczna jak na serwerze master. Jeśli nasza aplikacja nazywa się <code>facebook_killer</code> wykonujemy:</p>
<pre>mdkir /var/www/facebook_killer
chown capistrano /var/www/facebook_killer/
chgrp capistrano /var/www/facebook_killer/</pre>
<p>Lokalnie capistrano powinno nam przygotować niezbędne katalogi. Wywołujemy więc </p>
<pre>cap production deploy:setup</pre>
<p>Robimy deploy i ewentualnie poprawiamy co trzeba (instalujemy gemy, linkujemy katalogi).</p>
<pre>cap production deploy</pre>
<h3>Pliki konfiguracyjne</h3>
<p>Pora przygotować pliki konfiguracyjne. Wszystkie pliki oprócz <code>database.yml</code> powinny być identyczne jak na masterze. Należy więc dostosować ich zawartość, po czym zajmujemy się plikiem <code>database.yml</code>:</p>
<pre>vim /var/www/facebook_killer/shared/config/database.yml</pre>
<p>Ponieważ chcemy się połączyć z bazą na masterze, należy ustawić wszystko tak jak na masterze i dodać dwie linijki w sekcji production (port i adres serwera z bazą danych):</p>
<pre>
adapter: mysql
encoding: utf8
database: facebook_killer_prd
username: database_user
password: database_password
host: master_serwer_ip
port: 3306</pre>
<p>Odpalamy serwer ręcznie w trybie produkcyjnym, żeby zobaczyć czy działa. (W razie potrzeby należy doinstalować brakujące gemy):</p>
<pre>cd /var/www/facebook_killer/current/
RAILS_ENV=production script/server production</pre>
<p>Jeśli nie możemy teraz połączyć się bazą danych, znaczy to, że mamy odpowiednio zabezpieczony serwer produkcyjny. Wystarczy teraz tylko udostępnić bazę slave serwerowi. Jeśli jednak połączyliśmy się bez problemów, znaczy, to że zbyt łatwo każda osoba znająca hasło do bazy może się z nią zdalnie połączyć. Wnioski co to znaczy, należy wyciągnąć samemu.</p>
<h3>Zdalny dostęp do bazy</h3>
<p>Na serwerze z bazą (master serwer) należy ustawić dostęp do bazy danych. Poniższe podpunkt to ekstrakt ze świetnego przewodnika <a href="http://www.cyberciti.biz/tips/how-do-i-enable-remote-access-to-mysql-database-server.html">jak umożliwić zdalne łączenie się z serwerem bazy danych</a> (w języku angielskim).</p>
<p>Logujemy się na master serwer i szukamy pliku configuracyjnego MySQL: <code>my.cnf</code>. (W zależności od dystrybucji linuxa może być w w różnych katalogach.)</p>
<pre>
vim /etc/mysql/my.cnf
</pre>
<p>Należy zmodyfikować sekcję <code>[mysqld]</code>, upewaniając się, że linia <code>skip-networking</code> jest wykomentowana, a <code>bind-address</code> wskazuje na adres master serwera.</p>
<pre>
[mysqld]
user            = mysql
pid-file        = /var/run/mysqld/mysqld.pid
socket          = /var/run/mysqld/mysqld.sock
port            = 3306
basedir         = /usr
datadir         = /var/lib/mysql
tmpdir          = /tmp
bind-address    = master_serwer_ip
# skip-networking
</pre>
<p>Następnie należy zapisać plik i zrestartować serwer:</p>
<pre>/etc/init.d/mysql restart</pre>
<p>Kolejną rzeczą jest nadanie uprawnień użytkownikowi bazy danych łączącemu się z slave serwera. Łączymy się z bazą danych:</p>
<pre>mysql -u root -p mysql</pre>
<p>I nadajemy niezbędne uprawnienia.</p>
<pre>GRANT ALL ON facebook_killer_prd.* TO database_user@'slave_server_ip'
IDENTIFIED BY 'database_password';
exit</pre>
<p>Należy jeszcze otworzyć port <code>3306</code>. Bezpieczniej jest to zrobić umożliwiając wejścia tylko spod adresu ip slave serwera.</p>
<pre>
/sbin/iptables -A INPUT -i eth0 -s slave_serwer_ip -p tcp --destination-port 3306 -j ACCEPT
service iptables save</pre>
<p>Warto teraz odpalić serwer ręcznie i zobaczyć czy poprawnie łączymy się z bazą. Jeśli, występują jakieś problemy, polecam zajrzeć do <a href="http://www.cyberciti.biz/tips/how-do-i-enable-remote-access-to-mysql-database-server.html">oryginalnej instrukcji</a>.</p>
<h3>Ustawienie load balancingu</h3>
<p>Pora na najważniejszą rzecz. Skorzystamy z dyrektywy <a href="http://wiki.nginx.org/NginxHttpUpstreamModule">upstream</a>.</p>
<p>Na master serwerze ustawiamy:</p>
<pre># rozdziela żądania
 upstream www.facebook_killer.com {
     server 127.0.0.1:81;
     server slave_serwer_ip;
 }

 # nasłuchuje żądań i je przekazuje
 server {
     listen 80;
     server_name www.facebook_killer.com;
     location / {
       proxy_pass http://www.facebook_killer.com;
     }
}

 # uruchamia aplikację
 server {
     listen       81;
     server_name www.facebook_killer.com;
     root /var/www/facebook_killer/current/public;
     passenger_enabled on;
}</pre>
<p>W skrócie chodzi o to, że pierwsza dyrektywa server nasłuchuje i przekazuje żądania do upstream, które rozdziela je między serwer zdalny (slave_serwer) oraz lokalny (zdefiniowany w drugiej dyrektywie) na porcie 81. Warto zapoznać się z <a href="http://wiki.nginx.org/NginxHttpUpstreamModule">dokumentacją dyrektywy upstream</a>.</p>
<p>Przydatna uwaga: Upstream musi się nazywać tak samo jak domena (bez http), inaczej powyższa konfiguracja nie zadziała.</p>
<p>Na drugim serwerze konfiguracja jest dużo prostsza:</p>
<pre> server {
     listen 80:
     server_name www.facebook_killer.com;
     root /var/www/facebook_killer/current/public;
     passenger_enabled on;
}</pre>
<p>Czyli tak naprawdę jest to zwykła konfiguracja nginx. Domena facebook_killer powinna wkazywać oczywiście na adres master serwera. Restartujemy nginxa na obu serwerach i gotowe. Możemy szykować się na wykop effect. </p>
<h3>Uwagi końcowe</h3>
<p>Domyślnie nginx, wysyła przychodzące żądania do serwerwów po równo, lub zgodnie z wagami, które można przypisać poszczególnym serwerom. Rozwiązanie to może spowodować, że jeden z serwerów dostanie za duże obciążenie, w czasie gdy inny będzie wolny. Warto zatem rozważyć  użycie <a href="http://blog.phusion.nl/2008/10/29/phusion-passenger-now-with-global-queuing">Global Queue</a>. Działa ona w ten sposób, że tworzona jest jedna globalna kolejka żądań i są one przekazywane do serwerów dopiero wtedy, gdy serwery są w stanie obsłużyć kolejny request.</p>
<p>Oczywiście to jest najprostsza wersja takiej konfiguracji, która działa. Myślę, że powyższe wskazówki są dobrym punktem wyjścia do uruchomienia aplikacji działającej na kilku serwerach. Dodanie kolejnego serwera, po jego skonfigurowaniu to już tylko dodatkowa linjka w <code>upstream</code>. </p>
]]></content:encoded>
			<wfw:commentRss>http://rubysfera.pl/2010/08/aplikacja-dzialajaca-na-dwoch-serwerach/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Serwer continuous integration w Rubym &#8211; Integrity</title>
		<link>http://rubysfera.pl/2010/07/serwer-continous-integration-w-rubym-integrity/</link>
		<comments>http://rubysfera.pl/2010/07/serwer-continous-integration-w-rubym-integrity/#comments</comments>
		<pubDate>Wed, 28 Jul 2010 05:45:37 +0000</pubDate>
		<dc:creator>tjeden</dc:creator>
				<category><![CDATA[Tutoriale]]></category>
		<category><![CDATA[continous integration]]></category>

		<guid isPermaLink="false">http://rubysfera.pl/?p=165</guid>
		<description><![CDATA[Jak w czasie przerwy na kawę uruchomić swój własny serwer <strong>continous integration?</strong>]]></description>
			<content:encoded><![CDATA[<p>Jeśli zawsze chciałeś mieć serwer <a href="http://en.wikipedia.org/wiki/Continuous_integration">Continuous integration</a>, a właśnie teraz masz przerwę na kawę, to świetny moment by go zainstalować i zacząć używać w swoim projekcie. Jeśli nie wiesz dlaczego potrzebujesz serwera Continuous Integration (a potrzebujesz), poczytaj o tym na <a href="http://en.wikipedia.org/wiki/Continuous_integration">wikipedii</a>, lub obejrzyj <a href="http://vimeo.com/12609430">prezentację twórcy Integrity</a> z tegorocznego <a href="http://rubysfera.pl/2010/6/euruko-2010-dzien-pierwszy">EuRuKo</a>.</p>
<p>Potrzebne bedą:</p>
<ul>
<li>przerwa na kawę</li>
<li>ruby</li>
<li>git</li>
<li>jakiś stary komputer (może być też ten na którym pracujesz i tak, może być nowy)</li>
</ul>
<h3>O Integrity słów kilka</h3>
<p><a href="http://integrityapp.com/">Integrity</a> to zgrabna aplikacja napisana w Sinatrze, pełniąca rolę serwera Continuous Integration. Potrafi ona pobrać kod z repozytorium gita i uruchomić na nim dowolne komendy. Gotowi? Zatem zaczynamy.</p>
<h3>Instalacja Integrity</h3>
<p>Integrity, do zarządzania zależnościami korzysta z <a href="http://gembundler.com/">bundlera</a>. Jeśli jeszcze z niego nie korzystaliście, po prosty zainstalujcie go i podążajcie za poleceniami. Pewnie w krótce przyjrzymy się mu bliżej w osobnym poście.</p>
<pre class="sh_ruby">gem install bundler</pre>
<p>Integrity najlepiej pobrać z githuba i użyć ostatniej stabilnej wersji (v22):</p>
<pre class="sh_ruby">git clone git://github.com/integrity/integrity
git checkout -b deploy v22</pre>
<p>Następnie każemy bundlerowi zainstalować wszystykie potrzebne gemy i idziemy wstawić wodę na kawę/herbatę/yerba matę.</p>
<pre class="sh_ruby">bundle install
bundle lock</pre>
<p>Przygotujemy bazę danych.</p>
<pre class="sh_ruby">rake db</pre>
<p>Na chwilę obecną dostaniemy jakieś ostrzeżenia odnośnie datamappera, nie przeszkadzają nam one jednak uruchomić Integrity.</p>
<pre class="sh_ruby">bundle exec rackup</pre>
<p>Wystarczy teraz zajrzeć pod adres: <a href="http://localhost:9292/">http://localhost:9292/</a> i utworzyć swój pierwszy projekt.</p>
<div id="attachment_170" class="wp-caption alignnone" style="width: 310px"><a href="http://rubysfera.pl/2010/07/serwer-continous-integration-w-rubym-integrity/integrity1/" rel="attachment wp-att-170"><img src="http://rubysfera.pl/wp-content/uploads/2010/07/integrity1-300x200.png" alt="Tworzenie nowego projektu" title="integrity1" width="300" height="200" class="size-thumbnail wp-image-170" /></a><p class="wp-caption-text">Tworzenie nowego projektu</p></div>
<p>Po podaniu nazwy, adresu repozytorium i komendy do wykonania (<code>spec spec</code>), jesteśmy gotowi przeprowadzić pierwszy build, natykamy się tu jednak na komunikat:</p>
<pre class="sh_ruby">Integrity/.bundle/environment.rb:126:in `gem': rspec is not part of the
bundle. Add it to Gemfile. (Gem::LoadError)</pre>
<p>Oznacza to, że wszystkie potrzebne gemy musimy dorzucić do bundlera. Otwieramy zatem plik <code>Gemfile</code> i dopisujemy na jego końcu następującą linijkę:</p>
<pre class="sh_ruby">gem "rspec"</pre>
<p>Jeśli twoje testy wymagają innych gemów, musisz je również podać w pliku <code>Gemfile</code>. Następnie każemy bundlerowi zainstalować brakujący gem i idziemy zalać wrzątkiem kawę/herbatę/yerba matę.</p>
<pre class="sh_ruby">bundle install --relock</pre>
<p>Restartujemy naszą aplikację i odpalamy build jeszcze raz. Wszystkie testy przechodzą, a build nabiera zielonego koloru. Mamy działający serwer continuous integration. Prawda że szybko?</p>
<p><a rel="attachment wp-att-171" href="http://rubysfera.pl/2010/07/serwer-continous-integration-w-rubym-integrity/integrity2/"><img class="alignright size-thumbnail wp-image-171" title="integrity2" src="http://rubysfera.pl/wp-content/uploads/2010/07/integrity2-300x200.png" alt="Integrity - wygląd aplikacji" width="300" height="200" /></a></p>
<h3>Skąd Integrity wie, że testy przechodzą?</h3>
<p>Integrity korzysta z prostej zasady, że jeżeli unixowy program zakończył się bez błędów, to zwracana jest wartość 0, a jeśli błędy wystąpiły, wynik jest od zera różny. Ponieważ większość, jeśli nie wszystkie narzędzia do testowania w Rubym (test unit, rspec, cucumber) są zgodne z tymi założeniami, Integrity &#8222;wie&#8221;, czy testy znalazły błedy, czy też nie. Dzięki temu możliwe jest dodanie dowolnych narzędzi o ile zwracają one odpowiedni kod na wyjściu.</p>
<h3>Co dalej?</h3>
<p>Następnymi krokami powinno być uruchomienie Integrity na swoim ulubionym web serwerze i zautomatyzowaniu procesu. Buildy mogą być przygotowywane zarówno cyklicznie (np co godzinę), jak i z wykorzystaniem <a href="http://help.github.com/post-receive-hooks/">Post-Receive Hook</a>. Można również rozważyć ustawienie powiadomień na wypadek wystąpienia błędów. Jak to wszystko zrobić opisane zostało na <a href="http://integrityapp.com/">stronie Integrity</a>, ale to już temat do samodzielnego zgłębienia w czasie kolejnej przerwy na kawę.</p>
]]></content:encoded>
			<wfw:commentRss>http://rubysfera.pl/2010/07/serwer-continous-integration-w-rubym-integrity/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>10 porad o&#8230; Cucumber</title>
		<link>http://rubysfera.pl/2010/07/10-porad-o-cucumber/</link>
		<comments>http://rubysfera.pl/2010/07/10-porad-o-cucumber/#comments</comments>
		<pubDate>Tue, 06 Jul 2010 05:30:00 +0000</pubDate>
		<dc:creator>Czak</dc:creator>
				<category><![CDATA[Tutoriale]]></category>
		<category><![CDATA[bdd]]></category>
		<category><![CDATA[cucumber]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http:///2010/07/06/10-porad-o-cucumber</guid>
		<description><![CDATA[<p>W serii <strong>"10 porad o..."</strong> dziś na warsztacie - Cucumber.</p>]]></description>
			<content:encoded><![CDATA[<p><img class="alignright" src="http://rubysfera.pl/assets/2010/7/5/10-porad-cucumber.png" alt="" /></p>
<p>W <a href="http://rubysfera.pl/2010/3/10-porad-o-rspec">artykule o RSpecu</a> obiecałem drugą część poświęconą mockom i stubom i do tego tematu jeszcze wrócimy. Ale póki co naszła mnie wena na Ogórka. <a href="http://cukes.info/">Cucumber</a> to &#8211; obok RSpeca właśnie &#8211; drugi filar BDD w Rubym i jeśli jeszcze go nie znasz &#8211; przyszła już najwyższa pora.</p>
<p>Pierwsze kroki z Ogórkiem pomogą postawić <a href="http://rubysfera.pl/2010/4/sinatra-cucumber-capybara">dwie</a> <a href="http://rubysfera.pl/2010/5/uwierzytelnianie-w-sinatrze-z-data-mapperem">pierwsze</a> części naszego tutoriala.<br />
Poniższe 10 wskazówek przyda się raczej osobom, które miały już wcześniej do czynienia z Cucumberem.</p>
<h3>1. pickle</h3>
<p>O pickle <a href="http://rubysfera.pl/2010/3/warte-uwagi-pickle">pisałem już wcześniej</a> i będę pewnie trąbił o nim w nieskończoność. Jeśli masz wynieść z tego artykułu jedną rzecz &#8211; niech to będzie to. Przeczytaj, zainstaluj, korzystaj.</p>
<p>Pickle na GitHubie: <a href="http://github.com/ianwhite/pickle">http://github.com/ianwhite/pickle</a></p>
<h3>2. Szkice scenariuszy i tła</h3>
<p><code>Scenario outlines</code> i <code>Background</code> to jedne z podstawowych funkcji Cucumbera. Nie zaszkodzi jednak powtórzyć. A nuż ktoś usłyszy o tym właśnie pierwszy raz.</p>
<p>Oba te patenty służą do zmniejszenia duplikacji w scenariuszach.</p>
<p><code>Scenario outline</code> umożliwiają zastąpienie dwóch lub więcej podobnych scenariuszy jednym <em>szkicem</em>, do którego przekazujemy zestawy różnych opcji. Przykladowo zamiast:</p>
<pre class="sh_ruby">Scenario: User signs in with invalid email address
  Given a user exists with email: "email@person.com", password: "password"
  When I go to the sign in page
  And I fill in "email" with "somewrongemail"
  And I fill in "password" with "password"
  And I press "Login"
  Then I should see "Invalid e-mail address"

Scenario: User signs in with invalid password
  Given a user exists with email: "email@person.com", password: "password"
  When I go to the sign in page
  And I fill in "email" with "email@person.com"
  And I fill in "password" with "wrongpassword"
  And I press "Login"
  Then I should see "Invalid password"</pre>
<p>Możemy napisać:</p>
<pre class="sh_ruby">Scenario Outline: User signs in with invalid data
  Given a user exists with email: "email@person.com", password: "password"
  When I go to the sign in page
  And I fill in "email" with "&lt;email&gt;"
  And I fill in "password" with "&lt;password&gt;"
  And I press "Login"
  Then I should see "&lt;message&gt;"

  Examples: Variations of invalid login data
    | email            | password      | message                |
    | somewrongemail   | password      | Invalid e-mail address |
    | email@person.com | wrongpassword | Invalid password       |</pre>
<p>Dla każdego przykładu z tabeli <code>Examples</code> Cucumber wykona pełen scenariusz, wypełniając bloki <code>&lt;email&gt;</code> itp. odpowiednimi wartościami.</p>
<p>Inną metodą optymalizacji długości feature&#8217;ów jest <code>Background</code>. Jeśli w scenariuszach w jednym pliku powtarza się spora ilość <code>Given</code>ów, czasem warto wydzielić je do jednego wspólnego bloku <code>Background</code>.</p>
<p>Wychodząc od początkowych 2 scenariuszy, możemy spróbować tak:</p>
<pre class="sh_ruby">Background:
  Given a user exists with email: "email@person.com", password: "password"
  And I am on the sign in page

Scenario: User signs in with invalid email address
  When I fill in "email" with "somewrongemail"
  And I fill in "password" with "password"
  And I press "Login"
  Then I should see "Invalid e-mail address"

Scenario: User signs in with invalid password
  When I fill in "email" with "email@person.com"
  And I fill in "password" with "wrongpassword"
  And I press "Login"
  Then I should see "Invalid password"</pre>
<p>Na początku każdego ze scenariuszy zostanie wywołany w całości blok <code>Background</code>, dzięki czemu efekt pozostaje taki sam.</p>
<h3>3. Recycling kroków</h3>
<p>Już od pierwszych wersji Cucumbera była możliwość wykorzystania istniejących kroków w definicjach innych. Możliwe było więc wykorzystanie np. całego zestawu <code>web_steps</code> przy definiowaniu własnych, bardziej złożonych, jednak format zapisu był dość niezręczny:</p>
<pre class="sh_ruby">Given /^I log in as "([^\"]*)\/([^\"]*)"$/ do |email, password|
  Given %q{I go to the login page}
  Given %q{I fill in "E-mail" with "#{email}"}
  Given %q{I fill in "Hasło" with "#{password}"}
  Given %q{I press "Zaloguj się"}
end</pre>
<p>Na szczęście wprowadzona w wersji <strong>0.4.4</strong> metoda <code>steps</code> znacznie uprzyjemnia korzystanie z tego mechanizmu:</p>
<pre class="sh_ruby">Given /^I log in as "([^\"]*)\/([^\"]*)"$/ do |email, password|
  steps %Q{
    Given I go to the login page
    And I fill in "E-mail" with "#{email}"
    And I fill in "Hasło" with "#{password}"
    And I press "Zaloguj się"
  }
end</pre>
<h3>4. Popracuj nad regexami</h3>
<p>Sporą bolączką większych projektów jest duplikacja kodu. Dużo trąbi się o <strong>DRY</strong> ale pewna ilość redundancji i tak wkrada się do programów. Nie inaczej jest z testami. Dzięki temu, że kroki Cucumbera definiujemy przy użyciu wyrażeń regularnych, mamy do dyspozycji potężne narzędzie do DRY-owania testów.</p>
<p>Czy na pewno potrzebujesz oddzielne definicje dla <code>Given I am logged in</code> i <code>Given an admin signs in</code>? A co z krokami typu <code>Given I am logged in with email: "lukasz@czak.pl"</code>? Jeśli dobrze przemyślisz regexa, wszystkie możesz zdefiniować w jednym kroku, np:</p>
<pre class="sh_ruby">Given /^I am logged in(?: as (\w+))?(?: with email "([^\"]*)")?$/do |role, email|
  role ||= "user"
  email ||= "lukasz@czak.pl"
  password = "secret"
  steps %Q{
    Given a #{role}: "me" exists with email: "#{email}", password: "#{password}"
    And I go to the login page
    And I fill in "E-mail" with "#{email}"
    And I fill in "Password" with "#{password}"
    And I press "Login"
  }
end</pre>
<p>Taka definicja pasuje do kroków w kilku postaciach. Jeśli potrzebujesz w scenariuszu zalogowanego usera (bez wymagań co do jego roli czy emaila) możesz zapisać po prostu:</p>
<pre>Given I am logged in</pre>
<p>Jeśli potrzebujesz usera w konkretnej roli:</p>
<pre>Given I am logged in as admin
Given I am logged in as user</pre>
<p>Kiedy potrzebujesz usera z konkretnym emailem (który np. wykorzystujesz w dalszej części scenariusza):</p>
<pre>Given I am logged in with email: "ziom@czak.pl"</pre>
<p>I wreszcie aby stworzyć usera w konkretnej roli i ze specyficznym adresem e-mail:</p>
<pre>Given I am logged in as admin with email: "lukasz@czak.pl"</pre>
<p>Cała magia powyższej definicji zawiera się w bloku postaci <code>(?: as (\w+))?</code>. Dzięki niemu człon <code>as admin</code> czy <code>as user</code> zostanie zaakceptowany, a odpowiednia rola przechwycona do zmiennej <code>role</code>. Jednocześnie dzięki <code>?</code> na końcu cały ten blok jest opcjonalny.</p>
<p>Oczywiście z wyrażeniami regularnymi można tworzyć jeszcze większe cuda &#8211; to tylko jeden przykład.</p>
<h3>5. Debugger</h3>
<p>Długo zbywałem debugger jako narzędzie mało w Rubym przydatne, ale ostatnio przekonuję się do niego coraz bardziej. Kiedy już nie mam pomysłu dlaczego test się wysypuje, wstawiam do niego krok:</p>
<pre>Then debug</pre>
<p>..a w <code>debug_steps.rb</code> czeka definicja:</p>
<pre class="sh_ruby">Then /^debug$/ do
  debugger
end</pre>
<p>Pozostaje tylko odpalić scenariusz i pozwolić debuggerowi we wskazanym miejscu zatrzymać wykonywanie.</p>
<h3>6. Before, After i tagi</h3>
<p>Cucumber, na wzór RSpeca, posiada metody <code>Before</code> i <code>After</code>, dzięki którym możemy zdefiniować operacje wykonywane przed lub po każdym scenariuszu. Dzięki połączeniu z tagami może się to nam przydać do estetycznego uporządkowania ogórków.</p>
<p>Może się zdarzyć tak, że część naszych scenariuszy wymaga pewnych danych do działania. Z uporem maniaka wstawiamy więc do każdego z nich:</p>
<pre>Given a page exists with slug: "hello"
And a blog post exists with permalink: "hello"</pre>
<p>Jeśli powtarza się to w kilku scenariuszach, możemy nadać im tag, np <code>@seed</code>:</p>
<pre>@seed
Scenario: User reads the "Hello" page</pre>
<p>a w <code>support/seed_data.rb</code> wstawić:</p>
<pre class="sh_ruby">Before("@seed") do
  Factory(:page, :slug =&gt; "hello")
  Factory(:blog_post, :permalink =&gt; "hello")
end</pre>
<p>Teraz jeśli będzie potrzebny jeszcze jeden scenariusz wymagający tego samego &#8211; wystarczy nadać mu odpowiedni tag.</p>
<h3>7. Oszukać delayed_joba</h3>
<p>Delegowanie długich zadań do <a href="http://github.com/collectiveidea/delayed_job">delayed_job</a> jest już pewnym standardem, jednak testowanie takich asynchronicznych mechanizmów wciąż nie. Najprostsze rozwiązanie to małe oszustwo:</p>
<pre class="sh_ruby">Given /the system processes delayed jobs/ do
  Delayed::Job.work_off
end</pre>
<p>W żądanym miejscu scenariusza wstawiamy:</p>
<pre class="sh_ruby">...
And the system processes delayed jobs
...</pre>
<p>I mamy pewność, że cała dotychczasowa kolejka delayed_joba zostanie wykonana.</p>
<p>Wszystkie biblioteki wykonujące zadania w tle mają synchroniczną metodę wykonującą wszystko i można wykorzystać je analogicznie.</p>
<h3>8. Poznaj cucumber.yml</h3>
<p>Plik konfiguracyjny Cucumbera &#8211; <code>config/cucumber.yml</code> jest dosyć rozbudowany na &#8222;dzień dobry&#8221;, ale warto przyjrzeć mu się mimo wszystko i z kilku rzeczy skorzystać.</p>
<p>Pierwsza rzecz to <code>--format</code>, który może przyjąć 10 wartości, ale w domyślnej konfiguracji mamy do czynienia tylko z dwoma.</p>
<p>Głównym elementem <code>cucumber.yml</code> są jednak profile. Na starcie otrzymujemy dwa: <code>default</code> i <code>wip</code>. Jeśli w scenariuszach korzystamy aktywnie z tagów, warto utworzyć dodatkowy profil, który będzie uruchamiał jedynie te oznaczone (lub nie oznaczone) wskazanymi.</p>
<p>Wychodząc od domyślnego:</p>
<pre class="sh_ruby">default: &lt;%= std_opts %&amp;gt
wip: --tags @wip:3 --wip features</pre>
<p>Często dodaję dodatkowy profil <code>javascript</code> i zmieniam układ na:</p>
<pre class="sh_ruby">default: &lt;%= std_opts %&amp;gt --tags ~@javascript
wip: --tags @wip:3 --wip features
javascript: &lt;%= std_opts %&amp;gt</pre>
<p>Dzięki temu &#8222;normalne&#8221;, regularne uruchamianie ogórków pomija długo wykonujące się scenariusze wymagające <code>@javascript</code>, zaś uruchomienie pełnego zestawu &#8211; wraz z Selenium/Culerity wymaga wywołania:</p>
<pre class="sh_shell">cucumber --profile javascript</pre>
<h3>9. Pamiętaj o supporcie</h3>
<p>Pamiętaj, że każdy plik z <code>features/support</code> jest wczytywany przed wykonaniem całego zestawu testów. Nie ma więc potrzeby zapychać <code>features/support/env.rb</code>, skoro można np. dodać plik <code>features/support/capybara.rb</code>, a w nim:</p>
<pre class="sh_ruby">Capybara.default_driver     = :rack_test
Capybara.javascript_driver  = :culerity</pre>
<h3>10. Pożegnanie z ogórkiem</h3>
<p>Nie mniej ważną umiejętnością od wszystkich powyższych jest świadoma rezygnacja z Cucumbera i wybór lepszego narzędzia do określonego celu.</p>
<p>Modelowym przykładem jest testowanie integracji z zewnętrznymi usługami, np. z systemami płatności. Choć może kusić wysoki poziom abstrakcji Cucumbera i przeświadczenie, że &#8222;może wszystko to co i user&#8221;, bez spec&#8217;ów kontrolerów się w tym wypadku nie obejdzie.</p>
]]></content:encoded>
			<wfw:commentRss>http://rubysfera.pl/2010/07/10-porad-o-cucumber/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Prosta metoda na JRuby</title>
		<link>http://rubysfera.pl/2010/05/prosta-metoda-na-jruby/</link>
		<comments>http://rubysfera.pl/2010/05/prosta-metoda-na-jruby/#comments</comments>
		<pubDate>Wed, 19 May 2010 23:25:00 +0000</pubDate>
		<dc:creator>Czak</dc:creator>
				<category><![CDATA[Tutoriale]]></category>
		<category><![CDATA[capistrano]]></category>
		<category><![CDATA[glassfish]]></category>
		<category><![CDATA[jruby]]></category>
		<category><![CDATA[rails]]></category>

		<guid isPermaLink="false">http:///2010/05/19/prosta-metoda-na-jruby</guid>
		<description><![CDATA[<p>W tym artykule przedstawiamy najprostszą możliwą konfigurację JRuby on Rails</p>]]></description>
			<content:encoded><![CDATA[<p><img src="http://rubysfera.pl/assets/2010/5/19/glassfish.jpg" class="alignright"/></p>
<p>Tydzień temu <a href="http://jruby.org">JRuby</a> osiągnął spory milestone w wersji <a href="http://jruby.org/2010/05/12/jruby-1-5-0.html">1.5.0</a>, co utwierdziło mnie w przekonaniu, że jest to jeden z poważniejszych projektów w świecie Ruby&#8217;ego. Jest kilka przyczyn, dla których warto się nim zainteresować. Mówi się o wysokiej wydajności tej implementacji &#8211; nie ustępującej <a href="http://en.wikipedia.org/wiki/Ruby_MRI">MRI</a> 1.9. W środowiskach z rozbudowaną infrastrukturą JavaEE JRuby stanowi świetny punkt zaczepienia dla Ruby&#8217;ego.</p>
<p>Dla mnie podstawowym atutem JRuby&#8217;ego jest wygodny dostęp do multum bibliotek Javy, z których <a href="https://pdf-renderer.dev.java.net/">nie</a><a href="http://itextpdf.com/">jedna</a> dojrzałością przewyższa znane gemy w Rubym.</p>
<p>Decydując się na JRuby on Rails w budowanym właśnie przeze mnie projekcie obawiałem się, że będę musiał przeprosić się z <a href="http://tomcat.apache.org/">Tomcatem</a> czy <a href="http://www.mortbay.org/">Jettym</a>, grzebać się w XMLach i innych WARach. Obcując z wersją sprzed kilku miesięcy miałem też przykre doświadczenia z kompatybilnością niektórych gemów. Na szczęście JRuby 1.4.0 &#8211; a 1.5.0 tym bardziej &#8211; wszystkie te problemy rozwiązał.</p>
<p>Pojawiły się też w międzyczasie narzędzia ułatwiające deployment do tego stopnia, że nie jest on ani trochę trudniejszy od wdrożenia aplikacji na <a href="http://www.modrails.com/">Passengerze</a>. Nie trzeba też rezygnować z <a href="http://www.capify.org/index.php/Capistrano">Capistrano</a>.</p>
<p>Dla potomnych poniżej najprostszy scenariusz wdrożenia aplikacji JRuby on Rails.</p>
<h3>Przygotowanie</h3>
<p>Przed wdrożeniem upewnij się, że aplikacja na localhoście działa w pełni na JRubym. W moim projekcie tylko mały fragment korzysta z Javy, mam więc tendencję do odpalania:</p>
<pre class="sh_shell">
./script/server
</pre>
<p>zamiast</p>
<pre class="sh_shell">
jruby script/server
</pre>
<p>Nic nie stoi na przeszkodzie aby na komputerze mieć zarówno Ruby&#8217;ego MRI (czy <a href="http://www.rubyenterpriseedition.com/">EE</a>) obok JRuby. Możesz też oczywiście skorzystać z <a href="http://rvm.beginrescueend.com/">rvm</a>. Pamiętaj, że każdy interpreter ma swój własny zestaw gemów.</p>
<h3>JRuby i glassfish</h3>
<p>Na serwerze musi być oczywiście zainstalowany JRuby &#8211; ja zawsze instaluję do <code>/opt/jruby-1.x.x</code>, a wersję która mnie interesuje symlinkuję do <code>/opt/jruby</code>. Do <code>$PATH</code> dochodzi <code>/opt/jruby/bin</code>.</p>
<p>Zainstaluj gem <code>glassfish</code>:</p>
<pre class="sh_shell">
jgem install glassfish
</pre>
<p>I w sumie na tym koniec&#8230; serwer jest gotowy <img src='http://rubysfera.pl/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />  <a href="https://glassfish.dev.java.net/">Glassfish</a> to serwer aplikacji Java stworzony przez Suna, a dzięki jednemu developerowi jest dostępny <a href="http://glassfishgem.rubyforge.org/">w postaci gema</a>.</p>
<p>Z katalogu aplikacji możesz teraz wywołać:</p>
<pre class="sh_shell">
jruby -S glassfish
</pre>
<p>&#8230;i aplikacja działa na porcie 3000. Przydałoby się jednak odpalić serwer w tle. I może zmienić port? I restartować przy deployu&#8230; Pora więc na&#8230;</p>
<h3>Capistrano</h3>
<p>Do współpracy z Capistrano potrzebne są 2 kroki. Po pierwsze  musimy przygotować plik konfiguracyjny Glassfisha &#8211; tak aby odpalał się jako daemon i w odpowiednim miejscu zapisywał plik z <code>pid</code>em. Wywołaj w katalogu aplikacji:</p>
<pre class="sh_shell">
gfrake
</pre>
<p>Komenda wygeneruje podstawowy plik <code>config/glassfish.yml</code> z domyślnymi ustawieniami. Ustaw poniższe wartości:</p>
<pre>
...
environment: production
...
port: 3000  # (wedle uznania)
...
daemon:
  enable: true
  pid: tmp/pids/glassfish.pid
...
</pre>
<p>Konfig koniecznie przenieś do <code>shared</code> i pamiętaj o symlinkowaniu przy deployu (to temat na inną rozmowę).</p>
<p>Teraz pozostaje tylko przygotować kroki <code>deploy</code> w przepisie Capistrano:</p>
<pre class="sh_ruby">
namespace :deploy do
  desc "Start Glassfish Gem from a shutdown state"
  task :cold do
    start
  end

  desc "Stop a server running Glassfish Gem"
  task :stop do
    pid = "$(cat #{current_path}/tmp/pids/glassfish.pid)"
    run "if ps -p #{pid} > /dev/null; &#8617;
         then kill -INT #{pid}; &#8617;
         else echo 'Glassfish not running'; &#8617;
         fi"
  end

  desc "Starts a server running Glassfish Gem"
  task :start do
    run "cd #{current_path} &#038;&#038; glassfish"
  end

  desc "Restarts a server running Glassfish Gem"
  task :restart, :roles => :app do
    stop
    start
  end
end
</pre>
<p><code>start</code> to po prostu uruchomienie <code>glassfish</code>. Dzięki konfigowi uruchomi się w tle, a <strong>pid</strong> zapisze do <code>tmp/pids/glassfish.pid</code>.</p>
<p><code>stop</code> to sprawdzenie czy proces o danym <strong>pid</strong>zie istnieje i &#8211; jeśli tak &#8211; ubicie go.</p>
<p>Żadna filozofia.</p>
<p>W takiej konfiguracji Glassfish serwuje wszystko &#8211; również zasoby z <code>public</code>. Teoretycznie nie ma w tym nic złego, ale z punktu widzenia wydajności warto (warto?) tę funkcję zrzucić np. na Apache&#8217;a. Miało być jednak <strong>prosto</strong> więc na tym skończymy.</p>
<h3>Czarne chmury</h3>
<p><a href="http://glassfishgem.rubyforge.org/">Glassfish gem</a> jest stabilny, wydajny i super prosty w użyciu, ale ma jedną sporą wadę&#8230; nie jest już aktywnie rozwijany. W świetle <a href="http://www.oracle.com/us/sun/index.htm">zmian</a> jakie ostatnio przeszedł Sun, projekt ten &#8211; do tej pory wspierany przez firmę &#8211; nie &#8222;przeżył&#8221;.</p>
<p>Na horyzoncie widać już jednak potencjalnego następcę. A może raczej konkurenta. <a href="http://github.com/calavera/trinidad">trinidad</a> to Tomcat opakowany w gem i przygotowany do użycia prawie w taki sam sposób, który opisałem. Warto mieć na oku.</p>
<p>Kombinacja JRuby+Glassfish bardzo pozytywnie mnie zaskoczyła i zdecydowanie polecam ją wszystkim obawiającym się pierwszego kontaktu z JRubym.</p>
]]></content:encoded>
			<wfw:commentRss>http://rubysfera.pl/2010/05/prosta-metoda-na-jruby/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

