<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" version="2.0">
  <channel>
    <title>Drogomir</title>
    <link>http://blog.drogomir.com</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description />
    <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/drogomir" type="application/rss+xml" /><item>
      <title>Google chce przyśpieszyć internet</title>
      <description>&lt;p&gt;Nie od dziś wiadomo, że prędkość ładowania strony ma wpływ na akcje użytkowników. Badania prowadzone miedzy innymi przez Yahoo, Google i Amazon wskazały, że zmniejszenie czasu ładowania strony ma bezpośredni wpływ na ilość akcji wykonanych przez użytkowników (wyszukiwań lub w wypadku Amazona zakupionych przedmiotów).&lt;/p&gt;


	&lt;p&gt;Google odpalił niedawno stronę, na której &lt;a href="http://code.google.com/speed/index.html"&gt;zachęca i uczy jak przyśpieszyć działanie naszych stron i serwisów&lt;/a&gt;&lt;/p&gt;


	&lt;p&gt;Dodatkowo Google wypuścił narzędzie &lt;a href="http://code.google.com/speed/page-speed/"&gt;Page Speed&lt;/a&gt;, które jest rozszerzeniem do Firebuga i podobnie jak &lt;a href="http://developer.yahoo.com/yslow/"&gt;YSlow&lt;/a&gt; pomaga zbadać stronę pod kątem prędkości ładowania się poszczególnych komponentów. Oba te narzędzia dostarczają od razu praktycznych porad i opisów pomagających zrozumieć jak zoptymalizować stronę. Dla mnie są to niezbędne narzędzia przy pracy z serwisami internetowymi. Do tej pory używałem głównie YSlow, ale przy następnych optymalizacjach na pewno skorzystam z Page Speed.&lt;/p&gt;


	&lt;p&gt;Jeżeli jeszcze nie znacie tych narzędzi, gorąco polecam zapoznanie się z nimi.&lt;/p&gt;</description>
      <pubDate>Fri, 26 Jun 2009 21:11:00 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:bf0c93ec-7da9-47ca-aafb-4723feba7e15</guid>
      <author>Piotr Sarnacki</author>
      <link>http://blog.drogomir.com/articles/2009/06/26/google-chce-przy%C5%9Bpieszy%C4%87-internet</link>
      <category>Javascript</category>
      <category>Programowanie</category>
      <category>optymalizacja</category>
      <category>html</category>
      <category>pagespeed</category>
      <category>yslow</category>
      <trackback:ping>http://blog.drogomir.com/articles/trackback/61</trackback:ping>
    </item>
    <item>
      <title>YUI 3 beta</title>
      <description>&lt;p&gt;We wczorajszym poście na blogu &lt;span class="caps"&gt;YUI&lt;/span&gt; &lt;a href="http://www.yuiblog.com/blog/2009/06/24/yui3b1/"&gt;ogłoszono wersję beta &lt;span class="caps"&gt;YUI3&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;&lt;span class="caps"&gt;YUI&lt;/span&gt;&lt;/strong&gt; (Yahoo User Interface) jest frameworkiem javascript rozwijanym przez &lt;span class="caps"&gt;YAHOO&lt;/span&gt;, który dostarcza nie tylko niskopoziomowe funkcje pomagające przy pisaniu kodu javascript, ale też zestaw komponentów (takich jak różnego rodzaju okienka dialog, color picker, czy nawet &lt;a href="http://developer.yahoo.com/yui/editor/"&gt;bardzo dobry edytor &lt;span class="caps"&gt;WYSIWYG&lt;/span&gt;&lt;/a&gt;). &lt;span class="caps"&gt;YUI&lt;/span&gt; jest dojrzałą biblioteką używaną na stronach &lt;span class="caps"&gt;YAHOO&lt;/span&gt;, co zapewnia bardzo dobrą jakość. Sam team &lt;span class="caps"&gt;YUI&lt;/span&gt; to jedni z najlepszych specjalistów od frontendu &amp;#8211; zachęcam do czytania wpisów na &lt;a href="http://developer.yahoo.com/yui/editor/"&gt;ich blogu&lt;/a&gt;&lt;/p&gt;


	&lt;p&gt;To co najbardziej przekonywało mnie do używania &lt;span class="caps"&gt;YUI&lt;/span&gt;, to fakt dostarczenia całego zestawu narzędzi do budowania interfejsów użytkownika w javascripcie. W przypadku np. jQuery lekko może denerwować bardzo duże rozstrzelenie poszczególnych bibliotek. Są oczywiście takie projekty jak &lt;a href="http://jqueryui.com/"&gt;jqueryUI&lt;/a&gt;, ale większość pluginów trzeba ściągnąć z innych źródeł, a ich kod często pozostawia wiele do życzenia. W przypadku &lt;span class="caps"&gt;YUI&lt;/span&gt; mamy zwarty zestaw komponentów, łatwy do rozszerzania i rozwijany przez specjalistów w celu wykorzystania na stronach odwiedzanych codziennie przez miliony internautów.&lt;/p&gt;


	&lt;p&gt;Z drugiej strony to co było banalne w jQuery często było ciężkie do uzyskania w &lt;span class="caps"&gt;YUI&lt;/span&gt;. A jak wszyscy wiedzą jeżeli chodzi o zabawę z &lt;span class="caps"&gt;DOM&lt;/span&gt;, animacjami i ajaxem z jQuery jest ciężko wygrać. Dlatego gdy używałem komponentów &lt;span class="caps"&gt;YUI&lt;/span&gt; w jednym z projektów, w którym przy okazji używałem jQuery, to do manipulacji elementów &lt;span class="caps"&gt;DOM&lt;/span&gt; używałem jQuery, a z &lt;span class="caps"&gt;YUI&lt;/span&gt; wybierałem tylko komponenty.&lt;/p&gt;


	&lt;p&gt;Wersja trzecia &lt;span class="caps"&gt;YUI&lt;/span&gt; może to zmienić. Zespół z Yahoo postanowił przepisać bibliotekę zupełnie od nowa z naciskiem na lekkość i szybkość. Najważniejsze zmiany&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;zmienione &lt;span class="caps"&gt;API&lt;/span&gt; do manipulacji &lt;span class="caps"&gt;DOM&lt;/span&gt;, czyli &amp;#8220;jQueryzacja&amp;#8221; &amp;#8211; łańcuchy komend, proste funkcje typu addClass, remove, append itp.&lt;/li&gt;
		&lt;li&gt;ułatwiona praca z eventami&lt;/li&gt;
		&lt;li&gt;modularyzacja biblioteki&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;Najbardziej obiecująco wygląda ostatni punkt. Do tej pory poszczególne komponenty nie były modularne, co prowadziło do powtarzającego się  kodu w różnych komponentach. Dodatkowo jeżeli ktoś chciał stworzyć Tooltip dziedziczący po Overlay, to musiał wykorzystać wszystkie elementy, które Overlay zawiera. Jest to oczywiście zbędne wykorzystywanie pamięci i &lt;a href="http://developer.yahoo.com/yui/container/tooltip/index.html"&gt;Tooltip, który jest obecnie dostępny w &lt;span class="caps"&gt;YUI&lt;/span&gt;&lt;/a&gt; właśnie z tego powodu nie jest najlepszą możliwą implementacją.&lt;/p&gt;


	&lt;p&gt;&lt;span class="caps"&gt;W YUI3&lt;/span&gt; poszczególne funkcjonalności są rozbite do modułów. Dlatego, żeby zbudować wspomniany wyżej tooltip nie trzeba dziedziczyć po Overlay, tylko zmiksować (czy to nie brzmi znajomo?) na przykład: moduł pozycjonowania i moduł animacji. Dodatkowo można wmiksować poszczególne moduły nie tylko do klas, ale także instancji poszczególnych obiektów. Jeżeli będzie to rzeczywiście działało tak fajnie jak mówią programiści z &lt;span class="caps"&gt;YUI&lt;/span&gt; (polecam obejrzeć video ze &lt;a href="http://www.yuiblog.com/blog/2009/06/24/yui3b1/"&gt;zlinkowanego wcześniej posta&lt;/a&gt;), to &lt;span class="caps"&gt;YUI3&lt;/span&gt; na pewno zagości w moich projektach.&lt;/p&gt;


	&lt;p&gt;To co najbardziej denerwuje mnie obecnie w różnego rodzaju bibliotekach do jQuery czy prototype, to całkowite oderwanie poszczególnych bibliotek od siebie. Używam na przykład jqueryUI i żeby użyć tooltipa, muszę ściągnąć zupełnie inną bibliotekę, która jest napisana zupełnie inaczej i nie dzieli żadnego kodu z innymi bibliotekami (tutaj też wychodzi swoboda javascriptu, jeżeli ktoś próbował porównywać implementacje różnych bibliotek, to na pewno wie na ile różnych sposobów można zaimplementować te same funkcje). Jeszcze gorzej jest gdy trzeba napisać własne komponenty &amp;#8211; lekkość jQuery i brak oficjalnych bibliotek pomagających w takich wypadkach jest dość dużą przeszkodą.&lt;/p&gt;


	&lt;p&gt;W tym momencie &lt;span class="caps"&gt;YUI&lt;/span&gt; team zachęca programistów do używania &lt;span class="caps"&gt;YUI3&lt;/span&gt; w nowych projektach, szczególnie tych, które nie planują wykorzystywać dużej ilości widgetów obecnych w &lt;span class="caps"&gt;YUI2&lt;/span&gt;. Oficjalna wersja ma być dostępna w 3 kwartale tego roku. Rozwój można biblioteki śledzić &lt;a href="http://yuilibrary.com/projects/yui3/roadmap"&gt;tutaj&lt;/a&gt;&lt;/p&gt;</description>
      <pubDate>Thu, 25 Jun 2009 16:46:00 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:b3e80028-c073-453e-a9e1-c47d3a9dcb26</guid>
      <author>Piotr Sarnacki</author>
      <link>http://blog.drogomir.com/articles/2009/06/25/yui-3-beta</link>
      <category>Javascript</category>
      <category>jQuery</category>
      <category>javascript</category>
      <category>YUI</category>
      <category>Yahoo</category>
      <category>YUI3</category>
      <trackback:ping>http://blog.drogomir.com/articles/trackback/60</trackback:ping>
    </item>
    <item>
      <title>Co nowego w Rails3?</title>
      <description>&lt;p&gt;Ponad 4 miesiące temu światem Ruby&amp;#8217;iego zatrzęsła wiadomość o połączeniu się 2 popularnych frameworków &amp;#8211; Ruby on Rails i Merba. Dzisiaj, tylko kilka dni dzieli nas od ujrzenia &lt;a href="http://en.oreilly.com/rails2009/public/schedule/detail/7785"&gt;pierwszych aplikacji, które będą napisane w Rails 3&lt;/a&gt;. Carl Lerche (twórca między innymi routera do merba) oraz Yehuda Katz na tegorocznym RailsConf będą mówić o Rails3 i mountable apps.&lt;/p&gt;


	&lt;p&gt;Na stabilną wersję będzie trzeba jeszcze trochę poczekać, ale trzymam kciuki, żeby na RailsConf rzeczywiście udało im się pokazać działającą aplikację.&lt;/p&gt;


	&lt;p&gt;W tym poście chciałbym krótko opisać to co ma się znaleźć w Rails 3. Z niemałą niecierpliwością śledzę newsy i doniesienia o nowych railsach i nie mogę się już doczekać niektórych usprawnień.&lt;/p&gt;


	&lt;h3&gt;ActionORM (wcześniej ActiveORM)&lt;/h3&gt;


	&lt;p&gt;Zwolennicy Merba bardzo podkreślają w swoim frameworku niezależność od konkretnych technologii. Było to reklamowane głównie jako &amp;#8220;ORM agnosticism&amp;#8221; czyli możliwość podpięcia do Merba jednego z wielu &amp;#8220;ORMów&amp;#8221; (DataMapper, ActiveRecord, Sequel) w porównaniu do Railsowej monolityczności w postaci jednego słusznego ActiveRecorda.&lt;/p&gt;


	&lt;p&gt;Jaki właściwie jest problem w używaniu innego ORMa w naszej aplikacji? Na poziomie modeli i kontrolerów nie ma to z reguły większego znaczenia. Przecież Railsów nie obchodzi czy klasa w katalogu app/models dziedziczy po &lt;code&gt;ActiveRecord::Base&lt;/code&gt;, czy dołącza moduł: &lt;code&gt;include DataMapper::Resource&lt;/code&gt;&lt;/p&gt;


	&lt;p&gt;Kłopot zaczyna się kiedy chce się korzystać z wielu helperów, które jako argument przyjmują obiekt ActiveRecord. Najprostszy przykład:&lt;/p&gt;


&lt;pre class="brush: ruby"&gt;
&amp;lt;% form_for @article do |f| %&amp;gt;
  &amp;lt;%= f.text_field :title %&amp;gt;
&amp;lt;% end %&amp;gt;
&lt;/pre&gt;

	&lt;p&gt;Jeżeli &lt;code&gt;@article&lt;/code&gt; nie jest obiektem AR, to poprawność działania tej metody zależy tylko od tego czy interfejs danego ORMa tutaj używany jest taki sam. W tym akurat przypadku problemem może być sprawdzanie błędów w walidacji. Railsy domyślnie dodają wrapper do pól z błędami, więc jeżeli &lt;span class="caps"&gt;ORM&lt;/span&gt; ma inny interfejs do pobrania informacji o błędach, to metoda po prostu nie zadziała.&lt;/p&gt;


	&lt;p&gt;W tym momencie jest to w Railsach zrobione &lt;a href="http://github.com/rails/rails/blob/17e712d3a3d3934bb1f694d449d9a76a3ac715c1/actionpack/lib/action_view/helpers/active_record_helper.rb#L247"&gt;z użyciem alias_method_chain&lt;/a&gt; i jeżeli obiekt nie ma zaimplementowanej metody errors, to tag pozostaje niezmieniony, więc można samemu dołączyć swoją własną implementację lub dodać potrzebne metody do modelu. Jednak wszyscy chyba się zgodzą, że nie jest to najbardziej elegancki sposób.&lt;/p&gt;


	&lt;p&gt;Jeżeli chodzi o Merba, to sprawa wygląda tylko trochę lepiej niż w railsach. Jest co prawda wsparcie dla 3 najpopularniejszych &lt;span class="caps"&gt;ORM&lt;/span&gt;ów, ale implementacja nie pozwala na łatwe dodanie kolejnych &lt;span class="caps"&gt;ORM&lt;/span&gt;ów bez grzebania w kodzie. Jeżeli &lt;span class="caps"&gt;ORM&lt;/span&gt;, którego chcesz używać ma interfejs zgodny z DataMapperem, Sequelem lub ActiveRecordem, to wszystko jest ok, ale jeżeli jest to coś innego, to masz problem.&lt;/p&gt;


	&lt;p&gt;Odpowiedzią na to ma być ActionORM. Czym jest ActionORM? Jest to proste proxy dla obiektów. ActionORM udostępnia &lt;span class="caps"&gt;API&lt;/span&gt; takie jak ActiveRecord (dzięki temu w kodzie railsów nie będzie trzeba wiele zmieniać). W prostych słowach ActionORM ma sprawić, że obiekty innych &lt;span class="caps"&gt;ORM&lt;/span&gt;ów będą wyglądały jak obiekty ActiveRecord (czyli klasyczne wykorzystanie &lt;a href="http://en.wikipedia.org/wiki/Duck_typing"&gt;duck typing&lt;/a&gt;)&lt;/p&gt;


	&lt;p&gt;Tutaj jest przykład proxy dla Datamappera: &lt;a href="http://github.com/lancecarlson/rails/blob/0faae5b971c3dbf3b1c4ead19504580233bbc7fa/activeorm/lib/active_orm/proxies/datamapper_proxy.rb"&gt;http://github.com/lancecarlson/rails/blob/0faae5b971c3dbf3b1c4ead19504580233bbc7fa/activeorm/lib/active_orm/proxies/datamapper_proxy.rb&lt;/a&gt;&lt;/p&gt;


	&lt;p&gt;Różnice są jak widać niewielkie, ale podejrzewam, że będzie można dodać więcej metod, które się różnią pomiędzy implementacjami (oczywiście w granicach rozsądku, sprowadzanie całego interfejsu do jednego przypadku było by pozbawione sensu, chodzi o proste operacje, które każdy &lt;span class="caps"&gt;ORM&lt;/span&gt; ma rozwiązane podobnie, ale różni się &lt;span class="caps"&gt;API&lt;/span&gt;).&lt;/p&gt;


	&lt;h3&gt;Rack Middleware&lt;/h3&gt;


	&lt;p&gt;Railsy od jakiegoś czasu wykorzystują w pełni dobrodziejstwa &lt;a href="http://radarek.jogger.pl/2008/06/27/rack-niech-aplikacje-przemowia-wspolnym-jezykiem/"&gt;Rack&lt;/a&gt;. Co więcej, różne części frameworka są zaimplementowane jako rack middlewares. Kontroler, router, obsługa sesji i wiele innych rzeczy to teraz po prostu kolejne middlewares (przepraszam za te anglojęzyczne wstawki, ale naprawdę nie mam pojęcia jak to ładnie przetłumaczyć). Dzięki temu i dodaniu &lt;a href="http://weblog.rubyonrails.org/2008/12/17/introducing-rails-metal"&gt;Rails metal&lt;/a&gt; aplikacje są coraz bardziej modularne.&lt;/p&gt;


	&lt;p&gt;Programiści railsów dążą w tej chwili do jeszcze szerszego wykorzystania racka. Wszystko to idzie w stronę jak najłatwiejszego połączenia komponentów różnego typu. Na przykład możliwość podłączenia do routera kontrolerów railsowych, aplikacji sintatry i aplikacji merba (jako jedną aplikację oczywiście).&lt;/p&gt;


	&lt;h3&gt;Optymalizacja i refaktoryzacja&lt;/h3&gt;


	&lt;p&gt;Największą i najlepszą według mnie zmianą w railsach jest refaktoryzacja kodu ActionPack. Na czym ona polega? W bardzo prostych słowach: stworzony jest AbstractController, z którego dziedziczyć będą inne kontrolery, a w samym kodzie jest zastosowana dużo większa enkapsulacja. Jakie to ma znaczenie dla użytkowników railsów? Będzie istniał jeden interfejs dla wszystkich kontrolerów, dzięki czemu na przykład ActionController i ActionMailer będą mogły współdzielić funkcjonalność (żeby nie iść daleko, dopiero niedawno do mailera dodana została obsługa layoutów). Bardzo łatwe będzie też dodanie Parts znanych z merba (PartsController również dziedziczy w Merbie z AbstractControllera).&lt;/p&gt;


	&lt;p&gt;W chwili obecnej podobną funkcjonalność do Merb Parts udostępniają &lt;a href="http://cells.rubyforge.org/"&gt;Rails Cells&lt;/a&gt;, ale nie jest to rozwiązanie idealne (implementacja jest zagmatwana, w cellach widoczne są zmienne instancji z kontrolerów i innych celli, podejrzewam, że jest to wolniejsze niż parts).&lt;/p&gt;


	&lt;p&gt;Co jeszcze? Yehuda Katz wziął się między innymi za &lt;a href="http://yehudakatz.com/2009/01/16/status-update-a-fresh-look-at-callbacks/"&gt;optymalizację callbacków&lt;/a&gt;, czy bloku respond_to. Polecam również inne artykuły na temat refaktoryzacji na jego blogu.&lt;/p&gt;


	&lt;p&gt;Na pewno szybszy będzie też router. W chwili obecnej największym problemem jest to, że router generuje bardzo dużo metod (wszystkie metody _url i _path), co w rezultacie przyczynia się do bardzo wolnego startu aplikacji. W czasach mongreli nie miało to dużego znaczenia, bo aplikacje były odpalane raz i tylko sporadycznie restartowane. Teraz kiedy na wielu serwerach zainstalowany jest mod_passenger, czas startu aplikacji jest dużo ważniejszy &amp;#8211; instancje, które nie dostają requestów przez 5 minut (domyślne ustawienie) są wyłączane dzięki czemu nie zajmują zasobów.&lt;/p&gt;


	&lt;p&gt;Nowy router można przetestować już teraz. Po więcej odsyłam na &lt;a href="http://merbist.com/2009/04/14/merb-11-delayed/"&gt;the merbist&lt;/a&gt;&lt;/p&gt;


	&lt;h3&gt;Mountable apps&lt;/h3&gt;


	&lt;p&gt;Jest to jedna z tych rzeczy, na które czekam w Railsach 3 najbardziej. Dosłownie liczę godziny do rails conf i prezentacji na ich temat (mam nadzieję, że będą nagrywane, bo niestety nie miałem wolnych kilku tysięcy złotych, żeby się pojawić osobiście na konferencji ;-).&lt;/p&gt;


	&lt;p&gt;Jakieś namiastki mountable apps są już dostępne w postaci Rails Engines i Merb Slices. Jest to jakieś rozwiązanie, ale na pewno dalekie od idealnego. Żeby skorzystać z którejś z tych opcji trzeba napisać specyficzny rodzaj aplikacji, a każde z tych rozwiązań jest w niektórych miejscach niedopracowane. Celem mountable apps będzie możliwość łatwego połączenia 2 aplikacji bez żadnych zmian w kodzie.&lt;/p&gt;


	&lt;h3&gt;&lt;span class="caps"&gt;API&lt;/span&gt; dla pluginów&lt;/h3&gt;


	&lt;p&gt;Jedną z rzeczy, którą wypromował Merb jest publiczne i prywatne &lt;abbr title="Application Programming Interface"&gt;api&lt;/abbr&gt;. Dzięki temu pisanie pluginów nie wiąże się tam z używaniem alias_method_chain i ogólnie pojętym monkey patchingiem na każdym kroku. A jeżeli czegoś nie da się zrobić używając tylko publicznego api, to jest to bug. Jest to chyba jedna z trudniejszych rzeczy w całej refaktoryzacji. Nie wiadomo dokładnie czego będą potrzebować twórcy pluginów, niektóre metody trzeba będzie dopiero stworzyć.&lt;/p&gt;


	&lt;p&gt;Ogromnym plusem takiego podejścia jest to, że twórcy frameworka nie muszą się martwić o prywatne metody, ważne żeby publiczne &lt;span class="caps"&gt;API&lt;/span&gt; się nie zmieniało. Dzięki temu pluginy napisane zgodnie z wytycznymi, czyli nie używając prywatnego &lt;span class="caps"&gt;API&lt;/span&gt; nie będą się wysypywały na każdej kolejnej wersji (co bardzo często można zaobserwować w tym momencie), a jeżeli coś się zmieni w publicznym &lt;span class="caps"&gt;API&lt;/span&gt; przy okazji większych zmian, to twórcy pluginów będą mogli się o tym łatwo dowiedzieć bez śledzenia commitów na githubie.&lt;/p&gt;


	&lt;h3&gt;Podsumowanie&lt;/h3&gt;


	&lt;p&gt;Jestem zdania, że połączenie merba i railsów to jedna z najlepszych rzeczy, która mogła się przytrafić programistom webowym. Railsy będą szybsze, bardziej modularne i łatwiejsze w rozszerzaniu. Tylko czekać na wyniki refaktoryzacji :)&lt;/p&gt;


	&lt;p&gt;Postaram się w najbliższych tygodniach pisać o tym co dzieje się z Railsami3, jak idą prace i co jeszcze ciekawego będzie można zobaczyć.&lt;/p&gt;</description>
      <pubDate>Sun, 03 May 2009 20:10:00 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:2f0ea69a-8dda-49a1-b302-d5249e52dfdc</guid>
      <author>Piotr Sarnacki</author>
      <link>http://blog.drogomir.com/articles/2009/05/03/co-nowego-w-rails3</link>
      <category>Ruby on Rails</category>
      <category>rails</category>
      <category>rubyonrails</category>
      <category>ruby</category>
      <category>refaktoryzacja</category>
      <category>rails3</category>
      <category>merb</category>
      <trackback:ping>http://blog.drogomir.com/articles/trackback/59</trackback:ping>
    </item>
    <item>
      <title>Git - co zrobić gdy się scommituje za dużo zmian?</title>
      <description>&lt;p&gt;&lt;ins&gt;Jak zauważył słusznie Radarek w komentarzu taki sam efekt można uzyskać poleceniem &lt;code&gt;git reset --mixed HEAD~1&lt;/code&gt;. W tym wypadku można by treść całego posta wyrzucić do kosza, ale zostawię dla potomnych, żeby można było zobaczyć jak trzeba się nagimnastykować jeżeli się nie zajrzy do dokumentacji ;-)&lt;/ins&gt;&lt;/p&gt;


	&lt;p&gt;Czasami podczas pracy nad jakimiś większymi zmianami warto rozbić pracę na mniejsze commity. Zdarza mi się czasami dodać przełącznik -a z rozpędu, który commituje wszystkie zmiany. Najgorzej jest gdy wrzucam przy okazji nową wersję jakiegoś plugina do railsów. W takim wypadku zmiany w aplikacji są przeplatane zmianami w pluginie. Później gdy trzeba spojrzeć na coś w logach gita, może to dość znacznie utrudnić pracę.&lt;/p&gt;


	&lt;p&gt;Na szczęście git jest bardzo elastyczny i łatwo jest takie coś odwrócić.&lt;/p&gt;


	&lt;p&gt;Wyobraźmy sobie taką sytuację:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
  # przechodzę do nowej gałęzi, żeby zaimplementować nowy feature
  git checkout -b feature_200

  #....
  # tutaj dużo zmian, między innymi dodanie 
  # nowego pluginu, uaktualnienie innego, 
  # zmiany w samym kodzie itp. itd.

  # a teraz chcemy scommitować tylko zmiany w 
  # danym pluginie:
  git add vendor/plugins/acts_as_foobar
  git commit -m "Nowa wersja acts_as_foobar kompatybilna z railsami 2.3" -a
  # oj... dodałem -a, scommitowały się też 
  # zmiany w kodzie
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Co teraz? Nic trudnego :)&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
  # tworzymy patche względem mastera
  git format-patch master
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;W tym momencie powinno pojawić się sporo plików o nazwach na przykład:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
0001-Nowa-wersja-acts_as_foobar-kompatybilna-zrailsami-2.3.patch
#... ewentualnie więcej
&lt;/pre&gt;&lt;/code&gt;

Teraz trzeba wyrzucić &amp;#8220;zepsuty&amp;#8221; commit:
&lt;pre&gt;&lt;code&gt;
  git rebase -i HEAD~3
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Teraz powinien otworzyć się edytor, w którym widnieją linijki zaczynające się od słowa pick. Kasujemy linijkę z niechcianym commitem (tutaj uwaga &amp;#8211; jeżeli nie jesteście pewni, że wszystko gra, to najlepiej zrobić backup repo, po takim zabiegu commit po prostu zniknie). Po zapisaniu zmian commit powinien zostać wyrzucony z drzewka i można zaaplikować wcześniej stworzonego patcha:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
git apply 0001-Nowa-wersja-acts_as_foobar-kompatybilna-zrailsami-2.3.patch
&lt;/pre&gt;&lt;/code&gt;

	&lt;p&gt;W tym momencie wszystko powinno wyglądać tak jak przed commitem &amp;#8211; można teraz poprawić swój błąd.&lt;/p&gt;


	&lt;p&gt;Wiem, że to może się wydawać skomplikowane (szczególnie rebase), ale w praktyce zajmuje krótką chwilę, a dzięki takiemu zabiegowi nie ma bałaganu w repozytorium.&lt;/p&gt;


	&lt;p&gt;A może Wy macie jakieś ciekawe metody na rozwiązywanie problemów z gitem? Może inny sposób na powyższy problem?&lt;/p&gt;</description>
      <pubDate>Tue, 07 Apr 2009 11:40:00 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:22fc6e08-8dbd-4299-838c-3bd58c09c67e</guid>
      <author>Piotr Sarnacki</author>
      <link>http://blog.drogomir.com/articles/2009/04/07/git-co-zrobi%C4%87-gdy-si%C4%99-scommituje-za-du%C5%BCo-zmian</link>
      <category>Programowanie</category>
      <category>git</category>
      <category>rebase</category>
      <category>patch</category>
      <trackback:ping>http://blog.drogomir.com/articles/trackback/58</trackback:ping>
    </item>
    <item>
      <title>Refaktoryzacja Railsów</title>
      <description>&lt;p&gt;Niestety nie będzie to wpis o tym jak refaktoryzować swoją aplikację, ale raczej post o refaktoryzacji samego frameworka w ramach przygotowań do Rails 3.&lt;/p&gt;


	&lt;p&gt;&lt;a href="http://railsenvy.com/2008/12/31/rails-envy-podcast-episode-061-12-31-2008"&gt;Railsy pożarły mózg Merba i posiądą jego tajemne moce&lt;/a&gt; (zachęcam do wysłuchania tego podcastu, chłopaki od railsenvy genialnie mówią o tym co się dzieje w świecie railsów) &amp;#8211; o tym już &lt;a href="http://nhw.pl/pl/2008/12/rails-i-merb-w-jednym-staly-domu"&gt;każdy na pewno wie&lt;/a&gt;. Czy to dobrze? Oczywiście, że tak :)&lt;/p&gt;


	&lt;p&gt;Jeżeli ktoś dalej ma problemy z tą decyzją (podejrzewam, że może tak być w wypadku fanów merba), polecam prezentacją &lt;a href="http://railsconfeurope.blip.tv/file/1555560/"&gt;Living with legacy software&lt;/a&gt; wygłoszoną przez Davida Heinemeiera Hanssona &amp;#8211; nie jest w żaden sposób bezpośrednio związana z połączeniem, ale zmienia podejście do aplikacji i ich kodu.&lt;/p&gt;


	&lt;p&gt;&lt;a href="http://www.youtube.com/watch?v=UwI307EC63c&amp;#38;feature=related"&gt;Ale nie o to, nie o to, nie o to&lt;/a&gt;&lt;/p&gt;


	&lt;p&gt;&lt;a href="http://yehudakatz.com/"&gt;Yehuda Katz&lt;/a&gt; ostro wziął się do pracy jeszcze podczas świąt i co jakiś czas wrzuca na bloga informacje o tym jak refaktoryzuje i jakie ma plany wobec Railsów. Informacje traktujące o projektowaniu, refaktoryzacji i architekturze ciężko jest znaleźć w sieci, więc gorąco polecam śledzenie tego co pisze Yehuda &amp;#8211; do tej pory można przeczytać między innymi o enkapsulacji ActionView i ActionController czy o optymalizacji respond_to. Dodajcie sobie tego bloga do czytnika, naprawdę warto.&lt;/p&gt;


	&lt;p&gt;Co najlepsze, wiele z tych zmian dotyka tylko wewnętrznej implementacji railsów, więc można liczyć, że będą one dostępne dla ruby on rails 2.3.0.&lt;/p&gt;</description>
      <pubDate>Sat, 03 Jan 2009 21:45:00 +0100</pubDate>
      <guid isPermaLink="false">urn:uuid:d00a3c7e-d91a-4748-882a-02f5cd701d78</guid>
      <author>Piotr Sarnacki</author>
      <link>http://blog.drogomir.com/articles/2009/01/03/refaktoryzacja-rails%C3%B3w</link>
      <category>Ruby on Rails</category>
      <category>Programowanie</category>
      <category>rails</category>
      <category>rubyonrails</category>
      <category>refaktoryzacja</category>
      <category>rails3</category>
      <category>merb</category>
      <category>yehudakatz</category>
      <category>katz</category>
      <trackback:ping>http://blog.drogomir.com/articles/trackback/57</trackback:ping>
    </item>
    <item>
      <title>To self or not to self?</title>
      <description>&lt;p&gt;Czasami przeglądając kod różnych aplikacji można zauważyć kawałki wyglądające mniej więcej tak:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
  attr_accessor :price

  def total_price
    p = items.inject(0) {|sum, item| sum + item.price }
    # więcej kodu
    p
  end
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;W prawdziwej aplikacji można to zobaczyć &lt;a href="http://github.com/schof/spree/tree/master/app/models/order.rb#L100"&gt;na przykład w Spree&lt;/a&gt; (użycie tot zamiast total)&lt;/p&gt;


	&lt;p&gt;p oznacza tutaj zapewne price, ale autor kodu intuicyjnie stwierdził, że pisząc &amp;#8220;price =&amp;#8221;, zamiast stworzenia nowej zmiennej przypisze wartość na atrybut price.&lt;/p&gt;


	&lt;p&gt;Rzeczywiście jest to intuicyjne i całkiem bezpieczne, ale zupełnie niepotrzebne. Spokojnie i bez żadnego problemu można użyć price. Dlaczego?&lt;/p&gt;


	&lt;p&gt;W rubim można opuścić słowo self jeżeli chodzi o odczytanie wartości metody. Jeżeli więc bez zadeklarowania zmiennej price ktoś napisałby puts(price), to ruby zinterpretowałby to jako chęć wyświetlenia self.price. Inaczej jest z zapisywaniem. Jeżeli wywołana jest metoda price=, to ruby stworzy nową zmienną.&lt;/p&gt;


Na przykład taki kod:
&lt;pre&gt;&lt;code&gt;
  class Product
    attr_accessor :price

    def initialize(price)
      self.price = price
    end

    def do_something_with_price
      price = 10
      puts price
      puts self.price
    end
  end

  p = Product.new(20)
  p.do_something_with_price
&lt;/code&gt;&lt;/pre&gt;

Wypisze:
&lt;pre&gt;&lt;code&gt;
10
20
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Na koniec napiszę tylko, że mam mieszane uczucia co do korzystania z tych właściwości języka. Z jednej strony nie lubię jak w kodzie pałętają się skrótowe nazwy zmiennych, ale z drugiej strony taki zapis pokazuje, że chodzi nam o coś innego niż self.costam.&lt;/p&gt;


	&lt;p&gt;Ja z reguły staram się nie skracać nazw w takich wypadkach. Jakie jest wasze zdanie?&lt;/p&gt;</description>
      <pubDate>Sat, 15 Nov 2008 19:12:00 +0100</pubDate>
      <guid isPermaLink="false">urn:uuid:27a6da68-e7ae-4c93-8818-7e3e9ebb3dec</guid>
      <author>Piotr Sarnacki</author>
      <link>http://blog.drogomir.com/articles/2008/11/15/to-self-or-not-to-self</link>
      <category>Programowanie</category>
      <category>ruby</category>
      <category>self</category>
      <trackback:ping>http://blog.drogomir.com/articles/trackback/56</trackback:ping>
    </item>
    <item>
      <title>Jak użyć jQuery na stronie bez jQuery?</title>
      <description>&lt;p&gt;Czasami gdy chodzę po sieci chciałbym mieć możliwość wykonania jakiegoś kodu na stronie, na której aktualnie się znajduję. Do tego wystarczy konsola javascript w firebugu. Niestety można wtedy używać jedynie bibliotek, które są dołączone do strony. Co jeżeli nie ma tam jakiegoś prototype&amp;#8217;a czy innego jquery? Najczęściej potrzebne mi są selectory i traversing &amp;#8211; ostatnio na przykład chciałem na szybko policzyć jakieś dane na podstawie sporej tabeli na stronie internetowej. I co wtedy? Bawić się w getElementById i inne tego typu historie? Niefajne to, szczególnie jeżeli strona to jedna wielka tabelka bez prawie żadnych id, klas czy innych elementów pomocnych w wybraniu upragnionego kawałka.&lt;/p&gt;


	&lt;p&gt;Trochę ponad rok temu z kilkoma ludźmi pisałem startupa (po 2-3 miesiącach wszystko się rozpadło, ale było ciekawie), w którym duży nacisk był na dostarczenie prostych narzędzi (coś w rodzaju małego toolbara) do dowolnej strony internetowej. Oczywiście nie można zmusić właścicieli stron do wklejenia czegokolwiek na swoją stronę, ale można użyć zakładek przeglądarki, żeby coś takiego udostępnić.&lt;/p&gt;


	&lt;p&gt;Przeglądarki mogą obsługiwać adresy w postaci &amp;#8220;javascript: alert(&amp;#8216;Why are you so serious?&amp;#8217;);&amp;#8221;. Wystarczy wkleić coś takiego w pasku adresu &amp;#8211; oczywiście wyskoczy alert. A skoro użytkownik może dodać zakładkę do dowolnego adresu, to adres tej postaci też przejdzie.&lt;/p&gt;


	&lt;p&gt;Cały myk polegał więc na tym, żeby w kodzie javascript, który był dodawany do zakładek dołączyć jakąś bibliotekę (wtedy akurat używałem jQuery) i samą aplikację, która wyświetlała toolbar z różnymi opcjami.&lt;/p&gt;


	&lt;p&gt;Używając tej techniki można zrobić całkiem fajne rzeczy, ale w tym momencie ograniczę się do pokazania jak załączyć samą bibliotekę jQuery.&lt;/p&gt;


Kod wygląda mniej więcej tak:
&lt;pre&gt;&lt;code&gt;
(function( {
  var s = document.createElement('script');
  s.src="http://drogomir.com/jquery.js";
  document.body.appendChild(s);
})()
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Można jeszcze dodatkowo zrobić drugi skrypt, który dołączymy po jQuery, a w nim dodać na przykład jQuery.noConflict, albo jakiś inny kod wykonany po załączeniu jQuery.&lt;/p&gt;


	&lt;p&gt;Dodajcie do zakładek &lt;a href="javascript:(function()%20{%20var%20s%20=%20document.createElement('script');%20s.src='http://drogomir.com/jquery.js';%20document.body.appendChild(s);%20})()"&gt;tego linka&lt;/a&gt; i po wybraniu go na jakiekolwiek stronie jQuery zostanie dodane do skryptów na stronie.&lt;/p&gt;


	&lt;p&gt;Mam nadzieję, że komuś się przyda. Próbowałem znaleźć kod, o którym pisałem powyżej, który wyświetlał warstwę z toolboxem, z różnymi fajnymi opcjami, ale cholera chyba zniknął w pomroce dziejów. Będę musiał bardziej dbać o kod starych projektów, fajnie byłoby się teraz przyjrzeć pracy sprzed roku ;-)&lt;/p&gt;</description>
      <pubDate>Thu, 06 Nov 2008 23:07:00 +0100</pubDate>
      <guid isPermaLink="false">urn:uuid:3df02ffa-7d99-431f-95c1-2041b1a0bd84</guid>
      <author>Piotr Sarnacki</author>
      <link>http://blog.drogomir.com/articles/2008/11/06/jak-u%C5%BCy%C4%87-jquery-na-stronie-bez-jquery</link>
      <category>Javascript</category>
      <category>javascript</category>
      <trackback:ping>http://blog.drogomir.com/articles/trackback/55</trackback:ping>
    </item>
    <item>
      <title>Named scope</title>
      <description>&lt;p&gt;W railsach od jakiegoś czasu można używać &lt;a href="http://ar.rubyonrails.com/classes/ActiveRecord/NamedScope/ClassMethods.html"&gt;named_scope&lt;/a&gt;. Jest to bardzo fajny mechanizm umożliwiający łatwiejsze skonstruowanie zapytania używając wcześniej zdefiniowanych metod. Wcześniej był dostępny jako plugin has_finder.&lt;/p&gt;


Wygląda to mniej więcej tak:
&lt;pre&gt;&lt;code class="ruby"&gt;
  named_scope :active, :conditions =&amp;gt; { :active =&amp;gt; true }
  named_scope :paid, :conditions =&amp;gt; { :paid =&amp;gt; true }
  named_scope :recent, lambda { { :conditions =&amp;gt; ['created_at &amp;gt;= ?', 1.week.ago] } }

&lt;/code&gt;&lt;/pre&gt;

Po zdefiniowaniu takich sope&amp;#8217;ów (macie pomysł jak to spolszczyć?) można ich używać w ten sposób (zakładam, że scope&amp;#8217;y zostały zadeklarowane w modelu Product):
&lt;pre&gt;&lt;code class="ruby"&gt;
  Product.active.paid.recent
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Jak można łatwo zauważyć, scope&amp;#8217;y można łączyć w łańcuchy. Dzięki takiej konstrukcji otrzymujemy prosty i treściwy kod, który łatwo zrozumieć. Teraz coś lekko trudniejszego:&lt;/p&gt;


&lt;pre&gt;&lt;code class="ruby"&gt;
  named_scope :in_category, lambda { |category| { :conditions =&amp;gt; { :category_id =&amp;gt; category } } }

  # i użycie
  Product.active.recent.in_category(category)
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;O co chodzi? Jako 2 argument można przekazać lambdę, która zostanie wywołana przy użyciu scope&amp;#8217;a i powinna zwrócić Hash.&lt;/p&gt;


	&lt;p&gt;Ale to nie są jedyne zastosowania scope&amp;#8217;ów. Można do nich przekazać też inne parametry, które może przyjąć metoda find.&lt;/p&gt;


Na przykład order, offset i limit:
&lt;pre&gt;&lt;code class="ruby"&gt;
  named_scope :order, lambda { |*args| { :order =&amp;gt; args.first || "created_at DESC" } } 
  named_scope :offset lambda { |offset| { :offset =&amp;gt; offset } } 
  named_scope :limit, lambda { |*args| { :limit =&amp;gt; args.first || 10 } } 

  # i użycie:
  Product.active.order("id DESC").offset(10).limit
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;W pierwszym i trzecim scope&amp;#8217;ie zastosowałem trick, który pozwala na użycie zdefiniowanej wartości domyślnej w razie gdy żadna nie zostanie podana. `*args` pakuje argumenty do tablicy. Jeżeli args.first zwróci nil, to znaczy, że tablica jest pusta, czyli nie zostały podane żadne argumenty i trzeba zaaplikować wartość domyślną.&lt;/p&gt;


	&lt;p&gt;Coś jeszcze? Fajnie by było, żeby można było sortować nie tylko po wartościach z jednej tablicy&amp;#8230; a do tego wypadałoby użyć joins/include. Nic prostszego.&lt;/p&gt;


&lt;pre&gt;&lt;code class="ruby"&gt;
  named_scope :joins, lambda { |joins| { :joins =&amp;gt; joins } } 

  # a teraz można tak:
  Product.active.joins(:user).order('users.email')
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;How cool is that?&lt;/p&gt;


	&lt;p&gt;No i na koniec coś co ostatecznie przekonało mnie, że named_scope jest genialnym wynalazkiem. Jeżeli ktoś robił kiedyś formularze, w których można wybrać kilka opcji i na ich podstawie trzeba zbudować zapytanie, zapewne wie, że jest to nieco upierdliwe. Używając `named_scopes` można to zrobić bardzo łatwo.&lt;/p&gt;


	&lt;p&gt;Ryan Bates napisał plugin &lt;a href="http://github.com/ryanb/scope-builder/tree/master"&gt;scope_builder&lt;/a&gt;, dzięki któremu można to zrobić jeszcze łatwiej. Przypuśćmy, że mamy formę, w której można zaznaczyć kilka pól i po ich wysłaniu należy na ich podstawie pobrać odpowiednie rekordy z bazy.&lt;/p&gt;


&lt;pre&gt;&lt;code class="ruby"&gt;
  # przygotowujemy listę parametrów, które użytkownik może ustawić
  parameters = [:active, :paid, :recent, :title]
  # Tworzymy scope
  @products = Product.scope_builder
  # teraz można sprawdzić, które pola zostały zazanczone
  parameters.each do |param|
    @products.send(param) if params[param]
  end
  # na koniec można na przykład dodać paginację
  @products = @products.paginate(:per_page =&amp;gt; 10, :page =&amp;gt; params[:id])
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Dla mnie genialne. :) Można dzięki temu łatwiej tworzyć zaawansowane wyszukiwanie, sortowanie i inne tego typu rzeczy.&lt;/p&gt;


	&lt;p&gt;Oczywiście najlepiej jest zamknąć taki kawałek kodu jako metodę modelu, zgodnie ze &lt;a href="http://www.youtube.com/watch?v=91C7ax0UAAc"&gt;skinny controller, fat model&lt;/a&gt;, ale to pozostawię jako ćwiczenie ;-)&lt;/p&gt;</description>
      <pubDate>Fri, 03 Oct 2008 12:37:00 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:022e0d90-6941-4703-b442-78b95f508c04</guid>
      <author>Piotr Sarnacki</author>
      <link>http://blog.drogomir.com/articles/2008/10/03/named-scope</link>
      <category>Ruby on Rails</category>
      <category>Programowanie</category>
      <category>rails</category>
      <category>ruby</category>
      <category>named_scope</category>
      <trackback:ping>http://blog.drogomir.com/articles/trackback/54</trackback:ping>
    </item>
    <item>
      <title>Po dłuższej przerwie</title>
      <description>&lt;p&gt;Przez jakiś czas nie pisałem nic na blogu. Długo zbierałem się do napisania czegokolwiek, od dawien dawna miałem przetłumaczyć wpisy na moim &lt;a href="http://drogomir.com/blog"&gt;angielskojęzycznym blogusiu&lt;/a&gt;. Tak bardzo mi się nie chciało, że jak tylko siadałem do kompa z zamiarem przetłumaczenia czy napisania czegoś podobnego coś mnie odrzucało.&lt;/p&gt;


	&lt;p&gt;Dlatego, żeby więcej się nie męczyć podsumuję ten temat i podam linki &amp;#8211; większość ludzi, którzy tutaj trafią i tak na pewno zna angielski.&lt;/p&gt;


	&lt;p&gt;&lt;a href="http://github.com/drogus/apache-upload-progress-module/tree/master"&gt;Napisałem apache upload progress module&lt;/a&gt; do apacha. Moduł, dzięki któremu można pobrać dane o wysyłanych plikach. Format odpowiedzi oparłem o moduły tego typu dla &lt;a href="http://wiki.codemongers.com/NginxHttpUploadProgressModule"&gt;nginxa&lt;/a&gt; i &lt;a href="http://upload.lighttpd.net/index.html"&gt;lighttpd&lt;/a&gt; dlatego jeżeli wcześniej ktoś używał któregoś z nich, przesiadka będzie całkowicie bezbolesna. Sam używałem wcześniej nginx upload progress (głównie dlatego napisałem moduł do apacha) i po przerzuceniu aplikacji na apacha z nowym modułem nie trzea było zmieniać ani jednej linijki. Na angielskim blogu zamieściłem opis &lt;a href="http://drogomir.com/blog/2008/6/18/upload-progress-bar-with-mod_passenger-and-apache"&gt;instalacji i konfiguracji modułu&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;Żeby można było w miarę łatwo używać modułu napisałem także pluginy do &amp;#8220;prototype&amp;#8217;a&amp;#8221;http://github.com/drogus/prototype-upload-progress/tree/master i &lt;a href="http://github.com/drogus/jquery-upload-progress/tree/master"&gt;jquery&lt;/a&gt;, które obsługują pasek postępu. Przykłady są w repozytoriach, umieściłem je także &lt;a href="http://drogomir.com/files/blog/jquery-upload-progress/example/"&gt;na serwerze&lt;/a&gt; dla obczajenia w akcji. Popełniłem także tekst o tym &lt;a href="http://drogomir.com/blog/2008/6/30/upload-progress-script-with-safari-support"&gt;jak hackowałem plugin, żeby działał w safari&lt;/a&gt; &amp;#8211; safari w tym momencie nie było wcale lepsze od IE&amp;#8230; nawet powiedziałbym, że gorsze. Swoją drogą plugin nie działa w najnowszej operze (działał w 9.5 zdaje się), więc jeżeli ktoś ma chwile czasu i mógłby sprawdzić dlaczego i co można zrobić, żeby działał, to może wnieść swój wkład w rozwój (dodam, że nie jest to ta sama kwestia co dla safari, bo to już sprawdziłem) &amp;#8211; nie sądzę żebym miał teraz czas sam na tym siedzieć.&lt;/p&gt;


	&lt;p&gt;Dodatkowo napisałem jeszcze tekst o tym jak można fajnie &lt;a href="http://drogomir.com/blog/2008/7/3/tweaking-rails-app-with-jquery-part-i"&gt;uatrakcyjnić aplikację używając jQuery&lt;/a&gt;. Część pierwsza. Część druga będzie jak będę miał więcej czasu, czyli pewnie niezbyt szybko.&lt;/p&gt;


	&lt;p&gt;Pozdrowienia ze słonecznego Wrocławia, gdzie mam zamiar mieszkać przez najbliższy rok (miła odmiana od Pruszkowa :).&lt;/p&gt;</description>
      <pubDate>Tue, 30 Sep 2008 16:38:00 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:c70cc150-5a63-42e3-a8d6-f3611a2c355e</guid>
      <author>Piotr Sarnacki</author>
      <link>http://blog.drogomir.com/articles/2008/09/30/po-d%C5%82u%C5%BCszej-przerwie</link>
      <category>Javascript</category>
      <category>Ruby on Rails</category>
      <category>Programowanie</category>
      <category>rails</category>
      <category>javascript</category>
      <category>apache</category>
      <category>upload</category>
      <category>progress</category>
      <trackback:ping>http://blog.drogomir.com/articles/trackback/53</trackback:ping>
    </item>
    <item>
      <title>Mod passenger i Ruby Enterprise Edition</title>
      <description>&lt;p&gt;Dzisiaj opowiem wam bajeczkę o tym jak mod_passenger zeswatał ze sobą Apache&amp;#8217;a i Railsy. :)&lt;/p&gt;


Jeżeli ktoś sądzi, że z tego związku nic nie będzie, to rzucam kilka zalet:
	&lt;ul&gt;
	&lt;li&gt;nie trzeba bawić się w konfigurację proxy i martwić o zajęte porty&lt;/li&gt;
		&lt;li&gt;nie trzeba monitorować mongreli (ja &lt;a href="http://blog.drogomir.com/articles/2008/01/05/god-rb"&gt;używałem do tego goda&lt;/a&gt;)&lt;/li&gt;
		&lt;li&gt;ogólna prostota użycia&lt;/li&gt;
		&lt;li&gt;dzięki ruby enterprise można zaoszczędzić 33% pamięci&lt;/li&gt;
		&lt;li&gt;upload buffering, czyli nie musimy się martwić o upload dużych plików &amp;#8211; pliki są przesyłane do aplikacji railsowej dopiero, gdy zostaną w całości uploadowane na serwer&lt;/li&gt;
		&lt;li&gt;fair load balancing &amp;#8211; zapytania są wysyłane do procesów, które mają najmniej klientów w kolejce. żeby uzyskać coś takiego używając nginxa trzeba było &lt;a href="http://brainspl.at/articles/2007/11/09/a-fair-proxy-balancer-for-nginx-and-mongrel"&gt;instalować dodatkowy plugin&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;liczba instancji aplikacji nie jest sztywno określone. używając nginxa trzeba było przewidzieć jaka liczba serwerów railsów będzie potrzebna dla danej aplikacji, jeżeli na dany serwis wchodziło mało osób niewykorzystane serwery zjadały pamięć. mod_passenger uruchamia kolejne instancje w miarę potrzeb.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;Dodatkowo napisałem &lt;a href="http://github.com/drogus/apache-upload-progress-module/tree/master"&gt;apache upload progress module&lt;/a&gt; , dzięki czemu z mod_passengerem można sklecić pasek postępu wysyłania plików na serwer (forma dokładnie taka sama jak z Nginx Upload Progress, więc jeżeli ktoś go używał, to nawet nic nie będzie musiał zmieniać w skryptach).&lt;/p&gt;


	&lt;h3&gt;Mod Passenger&lt;/h3&gt;


	&lt;p&gt;Aktualnie najnowszą wersją mod_passengera jest 1.9.1 (RC2), &lt;a href="http://blog.phusion.nl/2008/06/16/phusion-passenger-20-rc-2-released/"&gt;instrukcja instalacji jest na blogu phusion&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;Po odpaleniu instalatora użytkownik jest prowadzony za rączkę, więc nikt nie powinien mieć probleów &amp;#8211; lubię takie podejście, nie muszę się zastanawiać nad tym co i jak mam zrobić i kopiować i wklejać kolejnych komend.&lt;/p&gt;


	&lt;p&gt;Mod passenger sprawuje się na serwerze bardzo fajnie, do tej pory nie miałem żadnych problemów. Żeby zrestartować aplikację rails wystarczy utworzyć plik tmp/restart.txt w katalogu aplikacji.&lt;/p&gt;


Po instalacji można jeszcze dodać w configu apacha linijkę:
&lt;pre&gt;&lt;code&gt;PassengerMaxPoolSize X&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Zamiast X wstawiamy maksymalną liczbę instancji aplikacji odpalonych na raz. W dokumentacji twierdzą, że dla VPSa z 256 megabajtami pamięci ram dobrą wartością będzie tutaj 2, a dla serwera dedykowanego z 2GB ramu 30. Większa liczba aplikacji to więcej zajętego ramu, ale też więcej requestów do obsłużenia w danej chwili.&lt;/p&gt;


	&lt;h3&gt;Ruby Enterprise Edition&lt;/h3&gt;


	&lt;p&gt;O ile o mod passengerze jest dużo informacji, to o ruby enterprise edition jeszcze niewiele. Według niektórych nazwa jest nietrafiona i niefajna, niektórym nie podoba się, że &lt;a href="http://judofyr.net/posts/ruby-fishy-edition.html"&gt;phusion chce się na &lt;span class="caps"&gt;REE&lt;/span&gt; wypromować&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;Mi to w zasadzie wszystko jedno jak się chłopaki z Phusion promują, kto na tym zarobi i jaka jest nazwa, o ile ta wersja będzie dobrze działała i rzeczywiście zmniejszała zużycie pamięci.&lt;/p&gt;


Żeby zainstalować ruby enterprise edition należy ściągnąć paczkę (najnowszą wersję paczki można znaleźć &lt;a href="http://rubyforge.org/projects/emm-ruby/"&gt;tutaj&lt;/a&gt;): 
&lt;pre&gt;&lt;code&gt;wget http://rubyforge.org/frs/download.php/38777/ruby-enterprise-1.8.6-20080623.tar.gz&lt;/code&gt;&lt;/pre&gt;

Następnie ją rozpakować:
&lt;pre&gt;&lt;code&gt;tar -zxvf ruby-enterprise-1.8.6-20080623.tar.gz&lt;/code&gt;&lt;/pre&gt;

i uruchomić installer:
&lt;pre&gt;&lt;code&gt;./ruby-enterprise-1.8.6-20080623/installer&lt;/code&gt;&lt;/pre&gt;

Tyle mówi opis na stronie &lt;span class="caps"&gt;REE&lt;/span&gt;, ale to jeszcze nie wszystko. Na początek można stworzyć dowiązanie symboliczne dla &lt;span class="caps"&gt;REE&lt;/span&gt;:
&lt;pre&gt;&lt;code&gt;ln -sf /opt/ruby-enterprise-1.8.6-20080623/bin/ruby /usr/bin/ruby-enterprise&lt;/code&gt;&lt;/pre&gt;

Użytkownicy gentoo muszą również skopiować plik auto_gem, który automatycznie jest w tej dystrybucji dodawany do &lt;span class="caps"&gt;RUBYOPT&lt;/span&gt;:
&lt;pre&gt;&lt;code&gt;cp /usr/lib/ruby/site_ruby/auto_gem.rb /opt/ruby-enterprise-1.8.6-20080623/lib/ruby/site_ruby&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Po zainstalowaniu rubiego instaluje się też kilka gemów, ale to tylko podstawowe &amp;#8211; resztę trzeba zainstalować samemu. Oczywiście można odpalić gem list i instalować kolejne gemy w danych wersjach, ale od czego mamy rubiego. Dosłownie w 2 minuty napisałem prosty skrypcik, który wyciąga nazwy i wersje gemów po czym instaluje je dla Ruby Enterprise Edition:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
`gem list`.split("\n").each do |line|
  if line =~ /([0-9a-zA-Z_\-]*) \((.*)\)/
    gem, versions = $1, $2.split(", ")
    versions.each do |version|
      puts "Installing #{gem}, version: #{version}" 
      puts `ruby-enterprise /opt/ruby-enterprise-1.8.6-20080623/bin/gem install #{gem} -y --version '#{version}' 2&amp;gt;&amp;#38;1`
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;

Teraz wystarczy dodać w configu apacha linijkę:
&lt;pre&gt;&lt;code&gt;RailsRuby /opt/ruby-enterprise-1.8.6-20080623/bin/ruby&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;I możemy cieszyć się naszym własnym wypicowanym apachem z mod_passengerem w korporacyjnej wersji ;-)&lt;/p&gt;</description>
      <pubDate>Tue, 17 Jun 2008 20:50:00 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:8b35d5b4-2cdf-49b2-831b-e0d041873b24</guid>
      <author>Piotr Sarnacki</author>
      <link>http://blog.drogomir.com/articles/2008/06/17/mod-passenger-i-ruby-enterprise-edition</link>
      <category>Ruby on Rails</category>
      <category>ruby</category>
      <category>enterprise</category>
      <category>instalacja</category>
      <category>mod_passenger</category>
      <category>apache</category>
      <trackback:ping>http://blog.drogomir.com/articles/trackback/51</trackback:ping>
    </item>
  </channel>
</rss>
