<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="/stylesheets/rss.css" type="text/css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>Jaros&#322;aw Zabie&#322;&#322;o - BLOG: Tag activerecord</title>
    <link>http://blog.zabiello.com/articles/tag/activerecord</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>moje notatki, linki, komentarze</description>
    <item>
      <title>W&#347;ciek&#322;y Zed i dyskusja wok&#243;&#322; Rubiego i Rails&#243;w</title>
      <description>&lt;p&gt;Ostatnio jest troch&#281; szumie w bran&#380;y po bezpardonowym (i niewybrednym) &lt;a href="http://www.zedshaw.com/rants/rails_is_a_ghetto.html"&gt;ataku Zeda Shaw&lt;/a&gt; uderzaj&#261;cym w kilka znanych postaci z kr&#281;g&#243;w Rubiego i Rails. Pewnie nikt by na to nie zwr&#243;ci&#322; uwagi gdyby nie to, &#380;e Zed jest autorem znanego projektu &lt;a href="http://mongrel.rubyforge.org/"&gt;Mongrel&lt;/a&gt;. Cho&#263; wpis si&#281; &#378;le czyta (bo jest rozwlek&#322;y i niepotrzebnie przeplatany ci&#261;g&#322;ymi przekle&#324;stwami autora) to zwr&#243;ci&#322; uwag&#281; na kilka istotnych problem&#243;w.&lt;/p&gt;


	&lt;p&gt;Autor zwraca uwag&#281;, &#380;e core team Rails&#243;w dosy&#263; opornie i wolno reaguje na podsy&#322;ane uwagi i poprawki. Fakt, jedn&#261; z poprawek jak&#261; kiedy&#347; podes&#322;a&#322;em odno&#347;nie &#378;le dzia&#322;aj&#261;cej funkcji render_to_string uwzgl&#281;dniono po.. o&#347;miu miesi&#261;cach. Zed si&#281; wkurzy&#322;, &#380;e ignorowano jego uwagi a potem i tak wychodzi&#322;o na jego. Tak z po&#322;owa core teamu to wg niego banda idiot&#243;w z wyp&#322;ukanymi przez &lt;span class="caps"&gt;PHP&lt;/span&gt;  m&#243;zgami. Ze swej strony bym m&#243;g&#322; do tej listy niekompetencji owej &amp;#8220;bandy&amp;#8221; te&#380; co&#347; do&#322;o&#380;y&#263;, ale to nie jest najwa&#380;niejsze. Jest reszta, kt&#243;ra dobrze robi swoj&#261; robot&#281;.  Ale mo&#380;e taka krytyka podzia&#322;a jak kube&#322; zimnej wody i w ko&#324;cu ca&#322;y core team zacznie skupia&#263; si&#281; na jako&#347;ci i optymalizacji ju&#380; istniej&#261;cego kodu. Bo jak nie, to programi&#347;ci Rails zaczn&#261; sukcesywnie przesuwa&#263; si&#281; do konkurencyjnego projektu &lt;a href="http://merbivore.com/"&gt;Merb&lt;/a&gt;. Ezra Zygmuntowicz udowodni&#322;, &#380;e mo&#380;na napisa&#263; &amp;#8220;lepsze Railsy&amp;#8221; (szybsze,  wielow&#261;tkowe i bardziej przejrzyste). Podoba mi si&#281; in&#380;ynieryjne podej&#347;cie Ezry Zygmuntowicza. Jego Merb jest bardzo &#322;adny, przejrzysty i szybki. Co ciekawe, Ezra zatrudni&#322; kilku developer&#243;w &lt;a href="http://rubini.us/"&gt;Rubiniusa&lt;/a&gt;. Zapowiada si&#281; &#380;e Railsy w ko&#324;cu spotka&#322;y bardzo trudn&#261; konkurencj&#281; (i bardzo dobrze). Sytuacj&#281; Rals&#243;w pog&#322;&#281;bia to, &#380;e nowe &lt;span class="caps"&gt;ORM&lt;/span&gt;&amp;#8217;y takie jak &lt;a href="http://datamapper.org/why.html"&gt;DataMapper&lt;/a&gt; i &lt;a href="http://code.google.com/p/ruby-sequel/"&gt;Sequel&lt;/a&gt; r&#243;wnie&#380; stanowi&#261; zagro&#380;enie dla dominacji &lt;a href="http://ar.rubyonrails.com/"&gt;Active Record&lt;/a&gt; nawet w kontek&#347;cie Rails&#243;w.&lt;/p&gt;


	&lt;h3&gt;PickAxe i inne ksi&#261;&#380;ki&lt;/h3&gt;


	&lt;p&gt;Zed przeprowadzi&#322; bardzo ciekaw&#261; krytyk&#281; chwalonej &lt;a href="http://helion.pl/ksiazki/prruby.htm"&gt;PickAxe&lt;/a&gt;. Ostro rozjecha&#322; autora za u&#380;ywanie g&#322;upich przyk&#322;ad&#243;w, niezgodnego z konwencjami Rubiego nazewnictwem zmiennych, i co najwa&#380;niejsze, omini&#281;cie szerokim &#322;ukiem najwa&#380;niejszej i najbardziej atrakcyjnej cechy Rubiego &amp;#8211; &#322;atwo&#347;ci metaprogramowania. PickAxe, zdaniem Zeda, odwo&#322;uje si&#281; do starych praktyk projektowania obiektowego z roku 2001. Zed idzie nawet dalej, uwa&#380;a &#380;e ta ksi&#261;&#380;ka promuje z&#322;e nawyki programistyczne i zach&#281;ca do pisania z&#322;ego kodu. Twierdzi nawet, &#380;e ta ksi&#261;&#380;ka zamiast pom&#243;c, zaszkodzi&#322;a Rubiemu aby wcze&#347;niej wyp&#322;yn&#261;&#322; na szerok&#261; scen&#281;.&lt;/p&gt;


	&lt;p&gt;Faktycznie, w latach 2001-2004 o Ruby praktycznie nikt nie s&#322;ysza&#322;. Jakie&#347; nieliczne wyj&#261;tki uczy&#322;y si&#281; Rubiego na &lt;a href="http://www.ruby-doc.org/docs/ProgrammingRuby/"&gt;ksi&#261;&#380;ce Dave&amp;#8217;a Thomasa&lt;/a&gt; ale j&#281;zyk jako taki by&#322; czym&#347; bardzo malo znanym. Sytuacj&#281; zmieni&#322;o dopiero pojawienie &lt;a href="http://rubyonrails.org"&gt;Ruby on Rails&lt;/a&gt; w 2005 roku, ktore spowodowa&#322;y &lt;strong&gt;znacz&#261;cy wzrost&lt;/strong&gt; popularno&#347;ci Rubiego (ja sam te&#380; zainteresowa&#322;em si&#281; te&#380; Railsami, a dopiero p&#243;&#378;niej Rubim). &lt;strong&gt;Dopiero Railsy pokaza&#322;y pi&#281;kno i moc metaprogramowania w Ruby&lt;/strong&gt;, co&#347; co zachwyci&#322;o rzesze ludzi, co&#347; czego nie maj&#261; inne j&#281;zyki. I nie wiem jak by si&#281; wysilano, nie da si&#281; uzyska&#263; tak pi&#281;knego i eleganckiego metaproramowania w &lt;span class="caps"&gt;PHP&lt;/span&gt;, Javie, czy nawet Pythonie. Zed bezpardonowo stwierdzi&#322;, &#380;e PickAxe tylko zaszkodzi&#322; Rubiemu zamiast mu pom&#243;c.&lt;/p&gt;


	&lt;p&gt;Wpierw mnie zaskoczy&#322;a ta opinia, ale p&#243;&#378;niej, jak si&#281; zastanowi&#322;em, to musz&#281; przyzna&#263; &#380;e du&#380;o w tym racji. Nigdy do mnie nie przemawia&#322;y u&#380;yte w ksi&#261;&#380;ce przyk&#322;ady. Ceni&#322;em j&#261; g&#322;&#243;wnie za to, &#380;e w og&#243;le jest cokolwiek na temat Rubiego, i &#380;e opisano bibliotek&#281; standardow&#261; Rubiego. Jestem ciekaw, co Zed by powiedzia&#322; na ksi&#261;&#380;k&#281; Hala Fultona &amp;#8220;The Ruby Way&amp;#8221;. Jej drugie wydanie w&#322;a&#347;nie &lt;a href="http://helion.pl/ksiazki/swruby.htm"&gt;zosta&#322;o wydane po polsku&lt;/a&gt;. Szkoda tylko, &#380;e ma w polskim wydaniu myl&#261;cy tytu&#322; sugeruj&#261;cy, &#380;e to tylko jaki&#347; zestaw 400 przyk&#322;ad&#243;w. Ksi&#261;&#380;k&#281; si&#281; dosy&#263; dobrze czyta. Lepiej ni&#380; PickAxe. T&#261; pierwsz&#261; troch&#281; traktuj&#281; jak podr&#281;cznik do bibliotek Rubiego.&lt;/p&gt;


	&lt;p&gt;Co ciekawe, dosta&#322;o si&#281; te&#380; troch&#281; ksi&#261;&#380;ce &lt;a href="http://helion.pl/ksiazki/agilep.htm"&gt;Agile&lt;/a&gt; :) Ale generalnie du&#380;o nie ma co si&#281; przyczepi&#263;. Ksi&#261;&#380;ka jest raczej dobrze napisana, szkoda tylko, &#380;e opisuje starsze Rails 1.2 a nie 2.0. No c&#243;&#380;, nie wiadomo czy wyjdzie trzecie wydanie, bo &lt;a href="http://www.loudthinking.com/about.html"&gt;&lt;span class="caps"&gt;DHH&lt;/span&gt;&lt;/a&gt; jako&#347; si&#281; do niego nie pali.&lt;/p&gt;


	&lt;p&gt;Z ciekawo&#347;ci sprawdzi&#322;em inn&#261; ksi&#261;&#380;k&#281;, polecan&#261; przez Zeda, &lt;a href="http://www.amazon.com/Rails-Way-Addison-Wesley-Professional-Ruby/dp/0321445619/"&gt;The Rails Way&lt;/a&gt;. Faktycznie wygl&#261;da na dobrze napisan&#261; i uwzgl&#281;dnia nowsze cechy Rails&#243;w. Jest dost&#281;pna online (cho&#263; nie za darmo) przez &lt;a href="http://safari.oreilly.com/"&gt;O&amp;#8217;Reilly Safari Books Online&lt;/a&gt; (tak w og&#243;le to &#347;wietny serwis, kt&#243;ry warto sobie zaprenumerowa&#263;).&lt;/p&gt;


	&lt;h3&gt;Rubinius, JRuby i Jubinius&lt;/h3&gt;


	&lt;p&gt;Zed si&#281; wkurzy&#322;, nabluzga&#322;, ale zwr&#243;ci&#322; uwag&#281; na kilka wa&#380;nych kwestii. Tak&#380;e odno&#347;nie samego Rubiego to pochwa&#322;a dosta&#322;a si&#281; &lt;a href="http://jruby.codehaus.org/"&gt;JRuby&lt;/a&gt; i &lt;a href="http://rubini.us/"&gt;Rubiniusowi&lt;/a&gt;. Szczeg&#243;lnie ten drugi mo&#380;e wkr&#243;tce kompletnie zagrozi&#263; dominacji &lt;span class="caps"&gt;MRI&lt;/span&gt; jaki jest u&#380;ywany w dzisiejszej, opartej na C, implemementacji Rubiego. Je&#347;li szybko nie powstanie kompletnie uko&#324;czony &lt;a href="http://www.atdot.net/yarv/"&gt;&lt;span class="caps"&gt;YARV&lt;/span&gt;&lt;/a&gt; (w&#322;&#261;czony do Ruby 1.9), to Rubinius zwyci&#281;&#380;y. Temat Rubiniusa jest on tematem naszych dyskusji na kanale &lt;span class="caps"&gt;IRC&lt;/span&gt; &lt;a href="irc://irc.eu.freenode.net/rubyonrails.pl"&gt;#rubyonrails.pl&lt;/a&gt;. Podej&#347;cie jest tu troch&#281; podobne do pythonowego &lt;a href="http://codespeak.net/pypy/dist/pypy/doc/news.html"&gt;PyPy&lt;/a&gt;, cho&#263; Rubinius nawi&#261;zuje bardziej do 30 lat do&#347;wiadcze&#324; &lt;a href="http://www.smalltalk.org/main/"&gt;Smalltalka&lt;/a&gt;. Celem jest stworzenie najszybszej wirtualnej maszyny Rubiego oraz &#322;atwego i szybkiego rozwoju dla samego Rubiego. Dzi&#281;ki temu, &#380;e mamy tu do czynienia z Ruby kt&#243;rego implementacja napisana jest w Ruby, znacznie &#322;atwiej jest rozwija&#263; j&#281;zyk.&lt;/p&gt;


	&lt;p&gt;Co ciekawe, autorzy JRuby zastanawiaj&#261; si&#281; czy nie zrobi&#263; podobnie. I ju&#380; s&#261; dyskusj&#281; o tym aby stworzy&#263; analogicznie &lt;a href="http://ola-bini.blogspot.com/2007/09/rubinius-is-important.html"&gt;Jubiniusa&lt;/a&gt;. Tak jak Rubinius w &#322;atwy spos&#243;b wci&#261;ga biblioteki napisane w C, Jubinius wci&#261;ga&#322;by te napisane w Javie. Jubinius mia&#322;by dodatkowo o tyle wygodniejsz&#261; sytuacj&#281;, &#380;e implementacja ca&#322;ej biblioteki standardowej Rubiego jest ju&#380; przepisana do Rubiego. Jubinius m&#243;g&#322;by z marszu wykorzysta&#263; ten kod.&lt;/p&gt;</description>
      <pubDate>Sun, 06 Jan 2008 23:49:00 +0100</pubDate>
      <guid isPermaLink="false">urn:uuid:1c2f3888-12a8-42dd-b190-ddd345a03248</guid>
      <author>Jaros&#322;aw Zabie&#322;&#322;o</author>
      <link>http://blog.zabiello.com/articles/2008/01/06/zed-ruby-rails</link>
      <category>mongrel</category>
      <category>ruby</category>
      <category>rubinius</category>
      <category>merb</category>
      <category>rails</category>
      <category>datamapper</category>
      <category>sequel</category>
      <category>activerecord</category>
      <category>jruby</category>
      <category>jubinius</category>
    </item>
    <item>
      <title>Sequel vs Active Record. Cz&#281;&#347;&#263; 2 - integracja Rails z Sequelem</title>
      <description>&lt;p&gt;W &lt;a href="http://blog.zabiello.com/articles/2007/12/13/slabosci-active-record"&gt;pierwszej cz&#281;&#347;ci&lt;/a&gt; troch&#281; wypunktowa&#322;em s&#322;abe strony standardowego &lt;span class="caps"&gt;ORM&lt;/span&gt;&amp;#8217;a u&#380;ywanego w Railsach. Najlepiej zast&#261;pi&#263; go szybszym i og&#243;lnie du&#380;o lepszym &lt;a href="http://code.google.com/p/ruby-sequel/"&gt;Sequelem&lt;/a&gt;. Mo&#380;na to zrobi&#263; na kilka sposob&#243;w: ca&#322;kowicie zast&#261;pi&#263; Active Record lub u&#380;ywa&#263; Sequela obok Active Record &amp;#8211; jak kto woli.&lt;/p&gt;


	&lt;p&gt;Zak&#322;adam, &#380;e na pocz&#261;tek mo&#380;e by&#347;my chcieli popr&#243;bowa&#263; Sequela tak, aby mo&#380;na by&#322;o szybko prze&#322;&#261;czy&#263; si&#281; z powrotem na Active Record. Po doinstalowaniu gema &lt;code&gt;sequel&lt;/code&gt; , nale&#380;y przej&#347;&#263; do pliku config/environment.rb i doda&#263; gdzie&#347; nast&#281;puj&#261;cy kod:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;sequel&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;
&lt;span class="constant"&gt;DB&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Sequel&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;mysql://login:haslo@localhost/nazwa_bazy&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Obiekt DB jest wielow&#261;tkowym po&#322;aczeniem z baz&#261; definiowan&#261; za pomoc&#261; &lt;span class="caps"&gt;URI&lt;/span&gt;. Jak kto&#347;, chce to mo&#380;na automatycznie zassa&#263; dane o bazie z pliku config/database.sql&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;sequel&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;
&lt;span class="ident"&gt;conf&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;YAML&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;load_file&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;config&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;database_configuration_file&lt;/span&gt;&lt;span class="punct"&gt;)[&lt;/span&gt;&lt;span class="constant"&gt;ENV&lt;/span&gt;&lt;span class="punct"&gt;['&lt;/span&gt;&lt;span class="string"&gt;RAILS_ENV&lt;/span&gt;&lt;span class="punct"&gt;']]&lt;/span&gt;
&lt;span class="constant"&gt;DB&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Sequel&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;&lt;span class="expr"&gt;#{conf['adapter']}&lt;/span&gt;://&lt;span class="expr"&gt;#{conf['username']}&lt;/span&gt;:&lt;span class="expr"&gt;#{conf['password]}&lt;/span&gt;@&lt;span class="expr"&gt;#{conf['host']}&lt;/span&gt;/&lt;span class="expr"&gt;#{conf['database']}&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;  &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Nast&#281;pnie w modelu mo&#380;na doda&#263; sobie warunek tak, aby trzyma&#263; obie wersje kodu, dla AR i dla Sequela (potem mo&#380;na wywali&#263; to, co nie jest potrzebne).&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="constant"&gt;DB&lt;/span&gt;
  &lt;span class="comment"&gt;# Wersja dla Sequel&lt;/span&gt;
  &lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Preference&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;Sequel&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Model&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:preferences&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;user&lt;/span&gt;
      &lt;span class="constant"&gt;User&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;filter&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:id&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ident"&gt;user_id&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;else&lt;/span&gt; 
  &lt;span class="comment"&gt;# Wersja dla Active Record&lt;/span&gt;
  &lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Preference&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;ActiveRecord&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Base&lt;/span&gt;
    &lt;span class="ident"&gt;belongs_to&lt;/span&gt; &lt;span class="symbol"&gt;:user&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Zamiast metody &lt;code&gt;user&lt;/code&gt; mo&#380;na u&#380;y&#263; makra &lt;code&gt;one_to_one :user, :from =&amp;gt; :User&lt;/code&gt; ale ja wol&#281; stworzy&#263; w&#322;asn&#261; metod&#281;. Robi nie tylko to samo, ale tak&#380;e nie trzeba pami&#281;ta&#263; dodatkowych opcji w razie nietypowej struktury. Poza tym w podanym przyk&#322;adzie zwracany jest obiekt proxy, a nie lista obiekt&#243;w. Daje to mo&#380;liwo&#347;ci poza zasi&#281;giem Active Record. Mog&#281; rozbudowywa&#263; zwracany obiekt o kolejne metody. Na ka&#380;dym etapie mam podgl&#261;d do wygenerowanego &lt;span class="caps"&gt;SQL&lt;/span&gt;&amp;#8217;a.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="constant"&gt;Preference&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;first&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;user&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;sql&lt;/span&gt;
&lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;SELECT * FROM users WHERE (`id` = 1)&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;

&lt;span class="constant"&gt;Preference&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;first&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;user&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;order&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:name&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;sql&lt;/span&gt;
&lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt;  &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;SELECT * FROM users WHERE (`id` = 1) ORDER BY `name`&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;

&lt;span class="constant"&gt;Preference&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;first&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;user&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;order&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:name&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;select&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:users&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;all&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;sql&lt;/span&gt;
&lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;SELECT users.* FROM users WHERE (`id` = 1) ORDER BY `name`&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Albo inny przyk&#322;ad&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Post&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;Sequel&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Model&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:posts&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;dataset.old_posts&lt;/span&gt;
    &lt;span class="ident"&gt;filter&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt;&lt;span class="symbol"&gt;:stamp&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="number"&gt;30&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;days&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;ago&lt;/span&gt;&lt;span class="punct"&gt;}&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;    
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;dataset.clean_old_posts&lt;/span&gt;
    &lt;span class="ident"&gt;old_posts&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;delete&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;I mo&#380;na teraz napisa&#263; tak:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="constant"&gt;Post&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;filter&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:category&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;ruby&lt;/span&gt;&lt;span class="punct"&gt;').&lt;/span&gt;&lt;span class="ident"&gt;clean_old_posts&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      <pubDate>Fri, 21 Dec 2007 13:27:00 +0100</pubDate>
      <guid isPermaLink="false">urn:uuid:06847b79-6ae4-4629-85e0-3c0c4a414d48</guid>
      <author>Jaros&#322;aw Zabie&#322;&#322;o</author>
      <link>http://blog.zabiello.com/articles/2007/12/21/integracja-rails-z-sequelem</link>
      <category>sequel</category>
      <category>rails</category>
      <category>activerecord</category>
    </item>
    <item>
      <title>Szybki start z Rails, Merb i Pylons</title>
      <description>&lt;p&gt;Celem tego tekstu jest por&#243;wnanie podstawowych czynno&#347;ci niezb&#281;dnych do tego aby uruchomi&#263; Rails, Merb oraz Pylons. Zak&#322;adam &#380;e u&#380;ywany b&#281;dzie&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://rubyonrails.org"&gt;Rails&lt;/a&gt; (v2.0.1) + &lt;a href="http://ar.rubyonrails.org/"&gt;Active Record&lt;/a&gt; + &lt;a href="http://haml.hamptoncatlin.com/"&gt;Haml&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href="http://merbivore.com/"&gt;Merb&lt;/a&gt; (v0.4.2)+ &lt;a href="http://code.google.com/p/ruby-sequel/"&gt;Sequel&lt;/a&gt; (v0.4.3) +  &lt;a href="http://haml.hamptoncatlin.com/"&gt;Haml&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href="http://pylonshq.com"&gt;Pylons&lt;/a&gt;  (v0.9.6.1) + &lt;a href="http://sqlalchemy.org"&gt;SQLAlchemy&lt;/a&gt;  + &lt;a href="http://makotemplates.org"&gt;Mako&lt;/a&gt;&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;Wpierw musimy (je&#347;li jeszcze nie mamy) poinstalowa&#263; stosowne biblioteki. W wypadku Rails i Merba musimy mie&#263; Rubiego i RubyGems oraz doinstalowane gemy:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;gem install -y rails haml merb sequel merb_sequel&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;W wypadku Pylons musimy mie&#263; zainstalowanego Pythona oraz pakiet setuptools daj&#261;cy mo&#380;liwo&#347;&#263; u&#380;ywania skryptu easy_install (taki odpowiednik RubyGems dla Pythona)&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;easy_install Pylons SQLAlchemy Mako&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;h2&gt;Tworzenie projektu:&lt;/h2&gt;


	&lt;h3&gt;Rails&lt;/h3&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;rails rails_app&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;h3&gt;Merb&lt;/h3&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;merb merb_app&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;h3&gt;Pylons&lt;/h3&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;paster create -t pylons pylons_app&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;h2&gt;Podpi&#281;cie do bazy&lt;/h2&gt;


	&lt;h3&gt;Rails&lt;/h3&gt;


	&lt;p&gt;Nale&#380;y w pliku config/database.yml wpisa&#263;:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_yaml "&gt;&lt;span class="key"&gt;shared&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; &lt;span class="anchor"&gt;&amp;amp;shared&lt;/span&gt;  
  &lt;span class="key"&gt;adapter&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; mysql
  &lt;span class="key"&gt;encoding&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; utf8
  &lt;span class="key"&gt;username&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; login
  &lt;span class="key"&gt;socket&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; /opt/local/var/run/mysql5/mysqld.sock
  &lt;span class="key"&gt;password&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; haslo
&lt;span class="key"&gt;development&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt;
  &lt;span class="key"&gt;database&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; rails_app
  &amp;lt;&amp;lt;: *shared
&lt;span class="key"&gt;test&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt;
  &lt;span class="key"&gt;database&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; test
  &amp;lt;&amp;lt;: *shared
&lt;span class="key"&gt;production&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt;
  &lt;span class="key"&gt;database&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; rails_app
  &amp;lt;&amp;lt;: *shared&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;h3&gt;Merb&lt;/h3&gt;


Tu jest tak samo jak w Rails z t&#261; r&#243;&#380;nic&#261;, &#380;e nie ma tego pliku. Nale&#380;y stworzy&#263; Plik config/database.yml:
&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_yaml "&gt;&lt;span class="document"&gt;---
  shared: &amp;amp;shared  &lt;/span&gt;
    &lt;span class="symbol"&gt;:adapter&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; mysql
    &lt;span class="symbol"&gt;:encoding&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; utf8
    &lt;span class="symbol"&gt;:username&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; login
    &lt;span class="symbol"&gt;:socket&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; /opt/local/var/run/mysql5/mysqld.sock
    &lt;span class="symbol"&gt;:password&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; haslo
  &lt;span class="key"&gt;development&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt;
    &lt;span class="symbol"&gt;:database&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; merb_app
    &amp;lt;&amp;lt;: *shared
  &lt;span class="key"&gt;test&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt;
    &lt;span class="symbol"&gt;:database&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; test
    &amp;lt;&amp;lt;: *shared
  &lt;span class="key"&gt;production&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt;
    &lt;span class="symbol"&gt;:database&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; merb_app
    &amp;lt;&amp;lt;: *shared&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;h3&gt;Pylons&lt;/h3&gt;


	&lt;p&gt;Tu, niestety, jest wi&#281;ksza zabawa, bo zar&#243;wno Pylons jak i SQLAlchemy s&#261; bardziej z&#322;o&#380;one.&lt;/p&gt;


	&lt;p&gt;W pliku development.ini wstawiamy:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;sqlalchemy&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;url&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;mysql&lt;/span&gt;&lt;span class="punct"&gt;:/&lt;/span&gt;&lt;span class="regex"&gt;&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;user&lt;/span&gt;&lt;span class="symbol"&gt;:haslo@localhost&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt;&lt;span class="number"&gt;3306&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;pylons_app&lt;/span&gt;
&lt;span class="ident"&gt;sqlalchemy&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;echo&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;True&lt;/span&gt;
&lt;span class="ident"&gt;sqlalchemy&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;pool_recycle&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="number"&gt;3600&lt;/span&gt;  &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Warto zwr&#243;ci&#263; uwag&#281;, &#380;e parametr &amp;#8216;pool_recycle&amp;#8217; zabezpiecza nas przed pewnym problemem w MySQL. Ot&#243;&#380; po paru godzinach nieaktywno&#347;ci, potrafi zrywa&#263; zestawione wcze&#347;niej po&#322;&#261;czenie. SQLAlchemy zabezpiecza si&#281; przed tym stukaj&#261;c do bazy co godzin&#281;. Active Record nie ma przed tym standardowo wbudowanego zabezpieczenia (sic!). Sequel za&#347; (te&#380; &amp;#8211; jak SQLAlchemy- pracuj&#261;cy wielow&#261;tkowo) wy&#322;apuje zerwane po&#322;&#261;czenia, czy&#347;ci je i zestawia z powrotem.&lt;/p&gt;


	&lt;p&gt;Musimy ustawi&#263; sesj&#281; dla SQLAlchemy. Dzia&#322;a i czy&#347;ci si&#281; po ka&#380;dym prze&#322;adowaniu przegl&#261;darki internetowej. W pliku pylons_app/lib/base.py wpisujemy:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="comment"&gt;# reszta pliku...&lt;/span&gt;
&lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="ident"&gt;pylons_app&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;model&lt;/span&gt; &lt;span class="ident"&gt;as&lt;/span&gt; &lt;span class="ident"&gt;model&lt;/span&gt;

&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;BaseController(WSGIController):&lt;/span&gt;

    &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;__call__&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;environ&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;start_response&lt;/span&gt;&lt;span class="punct"&gt;):&lt;/span&gt;
        &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Invoke the Controller&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
        &lt;span class="ident"&gt;conn&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;config&lt;/span&gt;&lt;span class="punct"&gt;['&lt;/span&gt;&lt;span class="string"&gt;pylons.g&lt;/span&gt;&lt;span class="punct"&gt;'].&lt;/span&gt;&lt;span class="ident"&gt;sa_engine&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;connect&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt;
        &lt;span class="ident"&gt;model&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;Session&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;bind&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="ident"&gt;conn&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
        &lt;span class="ident"&gt;try&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt;
            &lt;span class="keyword"&gt;return&lt;/span&gt; &lt;span class="constant"&gt;WSGIController&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;__call__&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;environ&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;start_response&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
        &lt;span class="ident"&gt;finally&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt;
            &lt;span class="ident"&gt;model&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;Session&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;remove&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt;
            &lt;span class="ident"&gt;conn&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;close&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt;
&lt;span class="comment"&gt;# reszta pliku...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;           

	&lt;h2&gt;Tworzenie modeli&lt;/h2&gt;


	&lt;h3&gt;Rails&lt;/h3&gt;


	&lt;p&gt;W Rails korzystamy z wbudowanych generator&#243;w kodu:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_shell "&gt;$ script/generate model User
-&amp;gt; app/models/user.rb
...
-&amp;gt; db/migrate/001_create_users.rb

$ script/generate model Post
-&amp;gt; app/models/post.rb
...
-&amp;gt; db/migrate/002_create_posts.rb&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Razem z modelami domy&#347;lnie s&#261; tworzone pliki z migracjami. Wpierw jednak zdefiniujmy relacje mi&#281;dzy modelami:&lt;/p&gt;


	&lt;p&gt;Plik app/models/post.rb:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Post&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;ActiveRecord&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Base&lt;/span&gt;
  &lt;span class="ident"&gt;belongs_to&lt;/span&gt; &lt;span class="symbol"&gt;:user&lt;/span&gt;
  &lt;span class="comment"&gt;# Albo to samo za pomoc&#261; tych metod:&lt;/span&gt;
  &lt;span class="comment"&gt;# def user&lt;/span&gt;
  &lt;span class="comment"&gt;#   User.find :first,:conditions =&amp;gt; [&amp;quot;id=?&amp;quot;, id]&lt;/span&gt;
  &lt;span class="comment"&gt;# end&lt;/span&gt;
  &lt;span class="comment"&gt;# def user=(item)  &lt;/span&gt;
  &lt;span class="comment"&gt;#   self.user_id = item.id&lt;/span&gt;
  &lt;span class="comment"&gt;# end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Plik app/models/user.rb:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;User&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;ActiveRecord&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Base&lt;/span&gt;
  &lt;span class="ident"&gt;has_many&lt;/span&gt; &lt;span class="symbol"&gt;:posts&lt;/span&gt;
  &lt;span class="comment"&gt;# Albo to samo bardziej bezpo&#347;rednio:&lt;/span&gt;
  &lt;span class="comment"&gt;# def posts&lt;/span&gt;
  &lt;span class="comment"&gt;#  Post.find :all, :conditions =&amp;gt; [&amp;quot;user_id=?&amp;quot;, id]&lt;/span&gt;
  &lt;span class="comment"&gt;# end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Zdefiniujemy nie tylko struktury tabel ale te&#380; wype&#322;nimy je przyk&#322;adowymi danymi.&lt;/p&gt;


	&lt;p&gt;Plik db/migrate/001_create_users.rb:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;CreateUsers&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;ActiveRecord&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Migration&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;self.up&lt;/span&gt;
    &lt;span class="ident"&gt;create_table&lt;/span&gt; &lt;span class="symbol"&gt;:users&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:force&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="constant"&gt;true&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;t&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;
      &lt;span class="ident"&gt;t&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;string&lt;/span&gt; &lt;span class="symbol"&gt;:name&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:null&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="constant"&gt;false&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
    &lt;span class="ident"&gt;add_index&lt;/span&gt; &lt;span class="symbol"&gt;:users&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:name&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:unique&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="constant"&gt;true&lt;/span&gt;
    &lt;span class="constant"&gt;User&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;create!&lt;/span&gt; &lt;span class="symbol"&gt;:name&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;Jarek&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;self.down&lt;/span&gt;
    &lt;span class="ident"&gt;drop_table&lt;/span&gt; &lt;span class="symbol"&gt;:users&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Plik db/migrate/001_create_posts.rb:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;CreatePosts&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;ActiveRecord&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Migration&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;self.up&lt;/span&gt;
    &lt;span class="ident"&gt;create_table&lt;/span&gt; &lt;span class="symbol"&gt;:posts&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:force&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="constant"&gt;true&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;t&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;
      &lt;span class="ident"&gt;t&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;integer&lt;/span&gt; &lt;span class="symbol"&gt;:user_id&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:null&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="constant"&gt;false&lt;/span&gt;
      &lt;span class="ident"&gt;t&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;string&lt;/span&gt; &lt;span class="symbol"&gt;:title&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:null&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="constant"&gt;false&lt;/span&gt;
      &lt;span class="ident"&gt;t&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;text&lt;/span&gt; &lt;span class="symbol"&gt;:body&lt;/span&gt;
      &lt;span class="ident"&gt;t&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;timestamps&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
    &lt;span class="ident"&gt;add_index&lt;/span&gt; &lt;span class="symbol"&gt;:posts&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:title&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:unique&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="constant"&gt;true&lt;/span&gt;
    &lt;span class="ident"&gt;post&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Post&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;
    &lt;span class="ident"&gt;post&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;title&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;Tytu&#322; artyku&#322;u&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;
    &lt;span class="ident"&gt;post&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;body&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;Tre&#347;&#263; artyku&#322;u&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;
    &lt;span class="ident"&gt;post&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;user&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;User&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;find_by_name&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;Jarek&lt;/span&gt;&lt;span class="punct"&gt;')&lt;/span&gt;
    &lt;span class="ident"&gt;post&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;save!&lt;/span&gt;    
  &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;self.down&lt;/span&gt;
    &lt;span class="ident"&gt;drop_table&lt;/span&gt; &lt;span class="symbol"&gt;:posts&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Uruchamiamy migracje:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;rake db:migrate&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Sprawd&#378;my interaktywnie (w konsoli, czyli po odpaleniu ruby script/console) czy modele dzia&#322;aj&#261; prawid&#322;owo.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="constant"&gt;User&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;find&lt;/span&gt; &lt;span class="symbol"&gt;:all&lt;/span&gt;
&lt;span class="comment"&gt;# =&amp;gt; [#&amp;lt;User id: 1, name: &amp;quot;Jarek&amp;quot;&amp;gt;]&lt;/span&gt;
&lt;span class="constant"&gt;User&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;find&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:first&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;posts&lt;/span&gt;
&lt;span class="comment"&gt;# =&amp;gt; [#&amp;lt;Post id: 1, user_id: 1, title: &amp;quot;Tytu&#322; artyku&#322;u&amp;quot;, body: &amp;quot;Tre&#347;&#263; artyku&#322;u&amp;quot;, created_at: &amp;quot;2007-12-15 18:16:27&amp;quot;, updated_at: &amp;quot;2007-12-15 18:16:27&amp;quot;&amp;gt;]&lt;/span&gt;
&lt;span class="constant"&gt;User&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;find&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:first&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;posts&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="punct"&gt;].&lt;/span&gt;&lt;span class="ident"&gt;title&lt;/span&gt;
&lt;span class="comment"&gt;# =&amp;gt; &amp;quot;Tytu&#322; artyku&#322;u&amp;quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;h2&gt;Merb&lt;/h2&gt;


	&lt;p&gt;Tu wpierw trzeba wybra&#263; jaki &lt;span class="caps"&gt;ORM&lt;/span&gt; chcemy u&#380;ywa&#263; (domy&#347;lnie Merb nie ma w&#322;aczonej obs&#322;ugi &#380;adnego). Operacja jest bardzo prosta. W pliku config/dependencies.rb odkomentujemy linijk&#281; tak aby by&#322;o:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;use_orm&lt;/span&gt; &lt;span class="symbol"&gt;:sequel&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Modele generujemy identycznymi generatorami jak w Rails.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_shell "&gt;$ script/generate model User
-&amp;gt; app/models/user.rb
...
-&amp;gt; schema/migrations/001_add_model_users.rb

$ script/generate model Post
-&amp;gt; app/models/post.rb
...
-&amp;gt; schema/migrations/002_add_model_posts.rb&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Definicja modeli.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Post&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;Sequel&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Model&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:posts&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="ident"&gt;one_to_one&lt;/span&gt; &lt;span class="symbol"&gt;:user&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:from&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="symbol"&gt;:Post&lt;/span&gt;
  &lt;span class="comment"&gt;# To samo co:&lt;/span&gt;
  &lt;span class="comment"&gt;# def user&lt;/span&gt;
  &lt;span class="comment"&gt;#   User.filter(:id=&amp;gt; user_id).first&lt;/span&gt;
  &lt;span class="comment"&gt;# end  &lt;/span&gt;
  &lt;span class="comment"&gt;# def user=(obj)&lt;/span&gt;
  &lt;span class="comment"&gt;#   self.user_id = obj.id&lt;/span&gt;
  &lt;span class="comment"&gt;# end  &lt;/span&gt;
  &lt;span class="comment"&gt;#&lt;/span&gt;
  &lt;span class="comment"&gt;# Merb nie ma automagicznego wype&#322;niania tre&#347;ci&#261;&lt;/span&gt;
  &lt;span class="comment"&gt;# p&#243;l o nazwach created_at czy updated_at&lt;/span&gt;
  &lt;span class="comment"&gt;# Ale posiada wywo&#322;ania zwrotne (te&#380; jak Rails)&lt;/span&gt;
  &lt;span class="ident"&gt;after_create&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;
    &lt;span class="ident"&gt;set&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:created_at&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="constant"&gt;Time&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;now&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="ident"&gt;set&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:updated_at&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="constant"&gt;Time&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;now&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="ident"&gt;after_update&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;
    &lt;span class="ident"&gt;set&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:updated_at&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="constant"&gt;Time&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;now&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;

&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;User&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;Sequel&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Model&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:users&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="ident"&gt;one_to_many&lt;/span&gt; &lt;span class="symbol"&gt;:posts&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:from&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="symbol"&gt;:posts&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:key&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="symbol"&gt;:user_id&lt;/span&gt;
  &lt;span class="comment"&gt;# To samo co:&lt;/span&gt;
  &lt;span class="comment"&gt;# def posts&lt;/span&gt;
  &lt;span class="comment"&gt;#   Post.filter :user_id =&amp;gt; pk&lt;/span&gt;
  &lt;span class="comment"&gt;# end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;W przeciwie&#324;stwie do Active Record, w Sequelu mo&#380;na zdefiniowa&#263; (&lt;a href="http://code.google.com/p/ruby-sequel/wiki/SequelModels"&gt;metod&#261; set_schema&lt;/a&gt;) struktur&#281; tabel w modelu (wtedy nie trzeba np. zagl&#261;da&#263; do migracji ani bazy, aby sobie przypomnie&#263; struktur&#281; tabeli). Ale aby oszcz&#281;dzi&#263; sobie pisania, zda&#322;em si&#281; tu na automatyczne rozpoznanie struktury tabel przez Rubiego.&lt;/p&gt;


	&lt;p&gt;Teraz pora na migracje. Sequel te&#380; je posiada, cho&#263; r&#243;&#380;ni&#261; si&#281; troszk&#281; sk&#322;adni&#261; do tych w Active Record.&lt;/p&gt;


	&lt;p&gt;Plik schema/migrations/001_add_mode_users.rb:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;AddModelUsers&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;Sequel&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Migration&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;up&lt;/span&gt;
    &lt;span class="ident"&gt;create_table!&lt;/span&gt; &lt;span class="symbol"&gt;:users&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;
      &lt;span class="ident"&gt;primary_key&lt;/span&gt; &lt;span class="symbol"&gt;:id&lt;/span&gt;
      &lt;span class="ident"&gt;varchar&lt;/span&gt; &lt;span class="symbol"&gt;:name&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:size&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="number"&gt;255&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:unique&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="constant"&gt;true&lt;/span&gt;      
    &lt;span class="keyword"&gt;end&lt;/span&gt;  
    &lt;span class="constant"&gt;User&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;create&lt;/span&gt; &lt;span class="symbol"&gt;:name&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;Jarek&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;down&lt;/span&gt;
    &lt;span class="ident"&gt;execute&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;DROP TABLE users&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Plik schema/migrations/002_add_mode_posts.rb:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;AddModelPosts&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;Sequel&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Migration&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;up&lt;/span&gt;
    &lt;span class="ident"&gt;create_table!&lt;/span&gt; &lt;span class="symbol"&gt;:posts&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;      
      &lt;span class="ident"&gt;primary_key&lt;/span&gt; &lt;span class="symbol"&gt;:id&lt;/span&gt; 
      &lt;span class="ident"&gt;integer&lt;/span&gt; &lt;span class="symbol"&gt;:user_id&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:null&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="constant"&gt;false&lt;/span&gt;
      &lt;span class="ident"&gt;varchar&lt;/span&gt; &lt;span class="symbol"&gt;:title&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:null&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="constant"&gt;false&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:unique&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="constant"&gt;true&lt;/span&gt;
      &lt;span class="ident"&gt;text&lt;/span&gt; &lt;span class="symbol"&gt;:body&lt;/span&gt;
      &lt;span class="ident"&gt;datetime&lt;/span&gt; &lt;span class="symbol"&gt;:created_at&lt;/span&gt; 
      &lt;span class="ident"&gt;datetime&lt;/span&gt; &lt;span class="symbol"&gt;:updated_at&lt;/span&gt; 
    &lt;span class="keyword"&gt;end&lt;/span&gt;    
    &lt;span class="ident"&gt;post&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Post&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;
    &lt;span class="ident"&gt;post&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;title&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;Tytu&#322; artyku&#322;u&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;
    &lt;span class="ident"&gt;post&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;body&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;Tre&#347;&#263; artyku&#322;u&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;
    &lt;span class="ident"&gt;post&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;user&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;User&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;filter&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:name=&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;'&lt;/span&gt;&lt;span class="string"&gt;Jarek&lt;/span&gt;&lt;span class="punct"&gt;').&lt;/span&gt;&lt;span class="ident"&gt;first&lt;/span&gt;
    &lt;span class="ident"&gt;post&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;save&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;down&lt;/span&gt;
    &lt;span class="ident"&gt;execute&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;DROP TABLE posts&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Uruchomienie migracji dzia&#322;a w Sequelu tak samo jak w Active Record (nawet parametr &lt;span class="caps"&gt;VERSION&lt;/span&gt; te&#380; tu dzia&#322;a).&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;rake sequel:db:migrate&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;No to pora na test z interaktywnej konsoli. Odpala si&#281; j&#261; przez:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;merb -i&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="constant"&gt;User&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;all&lt;/span&gt;
&lt;span class="comment"&gt;# =&amp;gt; [#&amp;lt;User:0x19477e8 @changed_columns=[], @values={:name=&amp;gt;&amp;quot;Jarek&amp;quot;, :id=&amp;gt;1}, newfalse]&lt;/span&gt;
&lt;span class="constant"&gt;User&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;first&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;posts&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="keyword"&gt;class 
&lt;/span&gt;&lt;span class="class"&gt;#&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ident"&gt;Sequel&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="ident"&gt;MySQL&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="ident"&gt;Dataset&lt;/span&gt;
&lt;span class="comment"&gt;# User.first.posts.sql&lt;/span&gt;
&lt;span class="comment"&gt;# =&amp;gt; &amp;quot;SELECT * FROM posts WHERE (`user_id` = 1)&amp;quot;        &lt;/span&gt;
&lt;span class="ident"&gt;User&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;first&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;posts&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;first&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;title&lt;/span&gt;
&lt;span class="comment"&gt;# =&amp;gt; &amp;quot;Tytu\305\202 artyku\305\202u&amp;quot;      &lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Sequel nie tylko jest szybszy i u&#380;ywa iterator&#243;w (oszcz&#281;dzaj&#261;&#263; przez to pami&#281;&#263;). Jest te&#380; wielow&#261;tkowy (u&#380;ywa puli w&#261;tk&#243;w) oraz pozwala na krokowy podgl&#261;d kodu &lt;span class="caps"&gt;SQL&lt;/span&gt; &lt;strong&gt;przed&lt;/strong&gt; jakimkolwiek przeslaniem kwerendy do bazy danych. Sequel r&#243;wnie&#380; nie zwraca liste obiektow &lt;span class="caps"&gt;ORM&lt;/span&gt; z bazy (jak Active Record) ale jeden, specjalny obiekt proxy. Pozwala to na interaktywne budowanie kodu w stopniu o wiele lepszym ni&#380; pozwala na to Active Record (czy nawet  DataMapper). Sequel ma r&#243;wnie&#380; &lt;a href="http://code.google.com/p/ruby-sequel/wiki/SequelModels"&gt;wbudowany cache modeli&lt;/a&gt; wsp&#243;&#322;pracuj&#261;cy z szybkim serwerem memcached.&lt;/p&gt;


	&lt;h3&gt;Pylons&lt;/h3&gt;


	&lt;p&gt;Poni&#380;sza konfiguracja jest inspirowana tekstem &lt;a href="http://wiki.pylonshq.com/display/pylonscookbook/SQLAlchemy+0.4+for+people+in+a+hurry"&gt;SQLAlchemy 0.4 for people in a hurry&lt;/a&gt;. Pylons nie wymaga aby ka&#380;dy model by&#322; w oddzielnym pliku, zatem u&#380;yjemy jednego. W pliku pylons_app/model/&lt;i&gt;init&lt;/i&gt;.py wpisujemy:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="comment"&gt;# -*- coding: utf8 -*-&lt;/span&gt;
&lt;span class="ident"&gt;from&lt;/span&gt; &lt;span class="ident"&gt;datetime&lt;/span&gt; &lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="ident"&gt;datetime&lt;/span&gt;

&lt;span class="comment"&gt;# Zgodnie z filozofi&#261; Pythona, importujemy tylko tylko interesuj&#261;ce nas symbole&lt;/span&gt;
&lt;span class="comment"&gt;# aby nie za&#347;mieca&#263; sobie przestrzeni nazw:&lt;/span&gt;

&lt;span class="ident"&gt;from&lt;/span&gt; &lt;span class="ident"&gt;pylons&lt;/span&gt; &lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="ident"&gt;config&lt;/span&gt;
&lt;span class="ident"&gt;from&lt;/span&gt; &lt;span class="ident"&gt;sqlalchemy&lt;/span&gt; &lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="constant"&gt;ForeignKey&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="constant"&gt;Column&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="constant"&gt;MetaData&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="constant"&gt;Table&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;types&lt;/span&gt;
&lt;span class="ident"&gt;from&lt;/span&gt; &lt;span class="ident"&gt;sqlalchemy&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;orm&lt;/span&gt; &lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="ident"&gt;mapper&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;relation&lt;/span&gt;
&lt;span class="ident"&gt;from&lt;/span&gt; &lt;span class="ident"&gt;sqlalchemy&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;orm&lt;/span&gt; &lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="ident"&gt;scoped_session&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;sessionmaker&lt;/span&gt;

&lt;span class="constant"&gt;Session&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;scoped_session&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;sessionmaker&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;autoflush&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="constant"&gt;True&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;transactional&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="constant"&gt;True&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;bind&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="ident"&gt;config&lt;/span&gt;&lt;span class="punct"&gt;['&lt;/span&gt;&lt;span class="string"&gt;pylons.g&lt;/span&gt;&lt;span class="punct"&gt;'].&lt;/span&gt;&lt;span class="ident"&gt;sa_engine&lt;/span&gt;&lt;span class="punct"&gt;))&lt;/span&gt;
&lt;span class="ident"&gt;metadata&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;MetaData&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt;

&lt;span class="comment"&gt;# Tworzymy definicje tabel:&lt;/span&gt;

&lt;span class="ident"&gt;table_users&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Table&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;users&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="ident"&gt;metadata&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;
  &lt;span class="constant"&gt;Column&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;id&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="ident"&gt;types&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;Integer&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;primary_key&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="constant"&gt;True&lt;/span&gt;&lt;span class="punct"&gt;),&lt;/span&gt;
  &lt;span class="constant"&gt;Column&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;name&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="ident"&gt;types&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;String&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;255&lt;/span&gt;&lt;span class="punct"&gt;))&lt;/span&gt;
  &lt;span class="punct"&gt;)&lt;/span&gt;
&lt;span class="ident"&gt;table_posts&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Table&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;posts&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="ident"&gt;metadata&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;
  &lt;span class="constant"&gt;Column&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;id&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="ident"&gt;types&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;Integer&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;primary_key&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="constant"&gt;True&lt;/span&gt;&lt;span class="punct"&gt;),&lt;/span&gt;
  &lt;span class="constant"&gt;Column&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;user_id&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="ident"&gt;types&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;Integer&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;ForeignKey&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;users.id&lt;/span&gt;&lt;span class="punct"&gt;')),&lt;/span&gt;
  &lt;span class="ident"&gt;Column&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;title&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="ident"&gt;types&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;Unicode&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;255&lt;/span&gt;&lt;span class="punct"&gt;)),&lt;/span&gt;
  &lt;span class="ident"&gt;Column&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;body&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="ident"&gt;types&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;Unicode&lt;/span&gt;&lt;span class="punct"&gt;),&lt;/span&gt;
  &lt;span class="ident"&gt;Column&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;created_at&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="ident"&gt;types&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;DateTime&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;default&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="ident"&gt;datetime&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;now&lt;/span&gt;&lt;span class="punct"&gt;),&lt;/span&gt;
  &lt;span class="constant"&gt;Column&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;updated_at&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="ident"&gt;types&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;DateTime&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;default&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="ident"&gt;datetime&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;now&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="punct"&gt;)&lt;/span&gt;
&lt;span class="comment"&gt;# Zamiast tego mo&#380;na automatycznie wci&#261;gn&#261;&#263; istniej&#261;c&#261; struktur&#281;:&lt;/span&gt;
&lt;span class="comment"&gt;#&lt;/span&gt;
&lt;span class="comment"&gt;# table_users = Table('users', metadata, autoload=True)&lt;/span&gt;
&lt;span class="comment"&gt;# table_posts = Table('posts', metadata, autoload=True)&lt;/span&gt;

&lt;span class="comment"&gt;# Tworzymy definicje modeli.&lt;/span&gt;

&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;User(object):&lt;/span&gt;
    &lt;span class="ident"&gt;pass&lt;/span&gt;
&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Post(object):&lt;/span&gt;
    &lt;span class="ident"&gt;pass&lt;/span&gt;

&lt;span class="comment"&gt;# Mapowanie ORM do klas SQLAlchemy i ustawienie&lt;/span&gt;
&lt;span class="comment"&gt;# relacji jeden-do-wielu&lt;/span&gt;
&lt;span class="ident"&gt;mapper&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;User&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;table_users&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;properties&lt;/span&gt;&lt;span class="punct"&gt;={'&lt;/span&gt;&lt;span class="string"&gt;posts&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="symbol"&gt;:relation&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;Post&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;backref&lt;/span&gt;&lt;span class="punct"&gt;='&lt;/span&gt;&lt;span class="string"&gt;user&lt;/span&gt;&lt;span class="punct"&gt;')})&lt;/span&gt;
&lt;span class="ident"&gt;mapper&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;Post&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;table_posts&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Wygl&#261;da to bardziej skomplikowanie, ale SQLAlchemy ma te&#380; wi&#281;ksze mo&#380;liwo&#347;ci. Zasadnicz&#261; r&#243;&#380;nic&#261; w SQLAlchemy jest rozdzielenie obiekt&#243;w &lt;span class="caps"&gt;ORM&lt;/span&gt; od obiekt&#243;w modelu biznesowego. Obiekty &lt;span class="caps"&gt;ORM&lt;/span&gt; zajmuj&#261; si&#281; mapowaniem struktur tabel do obiekt&#243;w Pythona. S&#261; one nast&#281;pnie &#322;&#261;czone z klasami SQLAlchemy. Takie rozdzielenie daje du&#380;o wi&#281;ksze mo&#380;liwo&#347;ci, bo mo&#380;na w modelu biznesowym nawet zamapowa&#263; kilka tabel do jednego modelu. SQLAlchemy ma du&#380;o innych mo&#380;liwo&#347;ci, o kt&#243;rych tu nie b&#281;d&#281; teraz pisa&#263;. W ka&#380;dym razie odbija si&#281; to na z&#322;o&#380;ono&#347;ci (ale i tak to jest pro&#347;ciej ni&#380; np. w javowym Hibernate).&lt;/p&gt;


	&lt;p&gt;Co z migracjami? Nie ma ich. Trzeba by by&#322;o je napisa&#263; (to w sumie nie jest trudna sprawa). Stworzmy jednak strukture tabel wraz z przyk&#322;adowymi danymi za pomoc&#261; SQLAlchemy. W tym celu ko&#324;c&#243;wka pliku pylons_app/websetup.py powinna wygl&#261;da&#263; nast&#281;puj&#261;co:&lt;/p&gt;


# pocz&#261;tek pliku&amp;#8230;
&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;setup_config&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;command&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;filename&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;section&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;vars&lt;/span&gt;&lt;span class="punct"&gt;):&lt;/span&gt;
    &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Place any commands to setup pylons_app here&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
    &lt;span class="ident"&gt;conf&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;appconfig&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;config:&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt; &lt;span class="punct"&gt;+&lt;/span&gt; &lt;span class="ident"&gt;filename&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="ident"&gt;load_environment&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;conf&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;global_conf&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;conf&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;local_conf&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;

    &lt;span class="ident"&gt;from&lt;/span&gt; &lt;span class="ident"&gt;pylons_app&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;model&lt;/span&gt; &lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="ident"&gt;metadata&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="constant"&gt;Session&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="constant"&gt;User&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="constant"&gt;Post&lt;/span&gt;

    &lt;span class="ident"&gt;log&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;info&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Creating tables&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;)&lt;/span&gt;
    &lt;span class="ident"&gt;metadata&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;create_all&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;bind&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="ident"&gt;config&lt;/span&gt;&lt;span class="punct"&gt;['&lt;/span&gt;&lt;span class="string"&gt;pylons.g&lt;/span&gt;&lt;span class="punct"&gt;'].&lt;/span&gt;&lt;span class="ident"&gt;sa_engine&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="ident"&gt;log&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;info&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Successfully setup&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;)&lt;/span&gt;

    &lt;span class="ident"&gt;log&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;info&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Adding some data to table 'users'&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;)&lt;/span&gt;
    &lt;span class="ident"&gt;user&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;User&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt;
    &lt;span class="ident"&gt;user&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;name&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;Jarek&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;
    &lt;span class="constant"&gt;Session&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;save&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;user&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="constant"&gt;Session&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;commit&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt;

    &lt;span class="ident"&gt;log&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;info&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Adding some data to table 'posts'&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;)&lt;/span&gt;
    &lt;span class="ident"&gt;user_query&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Session&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;query&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;User&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="ident"&gt;user_id&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;user_query&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;filter&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;User&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;name&lt;/span&gt; &lt;span class="punct"&gt;==&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;Jarek&lt;/span&gt;&lt;span class="punct"&gt;').&lt;/span&gt;&lt;span class="ident"&gt;one&lt;/span&gt;&lt;span class="punct"&gt;().&lt;/span&gt;&lt;span class="ident"&gt;id&lt;/span&gt;
    &lt;span class="ident"&gt;post&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Post&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt;
    &lt;span class="ident"&gt;post&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;title&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;Tytu&#322; artyku&#322;u&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;
    &lt;span class="ident"&gt;post&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;body&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;Tre&#347;&#263; artyku&#322;u&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;
    &lt;span class="ident"&gt;post&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;user_id&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;user_id&lt;/span&gt;
    &lt;span class="constant"&gt;Session&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;save&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;post&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="constant"&gt;Session&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;commit&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt;    
    &lt;span class="ident"&gt;log&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;info&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Data added.&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;W powy&#380;szym przyk&#322;adzie wida&#263; te&#380; pr&#243;bk&#281; sposobu w jaki u&#380;ywa si&#281; SQLAlchemy. Ka&#380;da operacja jest zamykana w ramach specjalnej sesji a sesja jest tworzona niezale&#380;nie dla ka&#380;dego w&#261;tku. W SQLAlchemy praktycznie w og&#243;le nie ma potrzeby si&#281;gania do kodu &lt;span class="caps"&gt;SQL&lt;/span&gt; tak jak to nagminnie wida&#263; w Active Record. Cho&#263; musz&#281; te&#380; przyzna&#263;, &#380;e Sequel tak&#380;e &#322;adnie daje sobie rad&#281; ze skomplikowanymi konstrukcjami bez konieczno&#347;ci uciekania si&#281; do surowego kodu &lt;span class="caps"&gt;SQL&lt;/span&gt;.&lt;/p&gt;


	&lt;p&gt;Uruchamiamy tworzenie tabel za pomoc&#261;:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;paster setup-app development.ini&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Interaktywny shell uruchamia si&#281; przez&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;paster shell&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Trzeba pami&#281;ta&#263;, &#380;e fakt uruchomienia konsoli nie oznacza, &#380;e mamy automatycznie powci&#261;gane modu&#322;y wszystkich modeli. W Pythonie nie ma magii, wszystko nale&#380;y jawnie zaimportowa&#263;. Tak&#380;e i nasz projekt.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;from&lt;/span&gt; &lt;span class="ident"&gt;pylons_app&lt;/span&gt; &lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="punct"&gt;*&lt;/span&gt;
&lt;span class="ident"&gt;print&lt;/span&gt; &lt;span class="ident"&gt;model&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;User&lt;/span&gt;
&lt;span class="comment"&gt;# =&amp;gt; &amp;lt;class 'pylons_app.model.User'&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;h2&gt;Tworzenie kontrolera i prostego widoku.&lt;/h2&gt;


	&lt;h3&gt;Rails&lt;/h3&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;script/generate controller home
# =&amp;gt; app/controllers/home_controller.rb&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Plik kontrolera (app/controller/home_controller.rb):&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;HomeController&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;ApplicationController&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;index&lt;/span&gt;
    &lt;span class="attribute"&gt;@user&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;User&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;find&lt;/span&gt; &lt;span class="symbol"&gt;:first&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Aby u&#380;y&#263; Haml zamiast ERb musimy w katalogu projektu odpali&#263; komend&#281; (nie zapomnij o kropce, kt&#243;ra oznacza tu bie&#380;&#261;cy katalog):&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;haml --rails .&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Plik widok (app/views/home/index.html.haml):&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_haml "&gt;U&#380;ytkownik
= @user.name
posiada post(y)
%ul
  - @user.posts.each do |post|
    %li= post.title&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Serwer uruchamiamy klasycznie&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;script/server&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;h3&gt;Merb&lt;/h3&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;script/generate controller home
# =&amp;gt; app/controllers/home.rb&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

Plik kontrolera (app/controllers/home.r):
&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Home&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;Application&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;index&lt;/span&gt;
    &lt;span class="attribute"&gt;@user&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;User&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;first&lt;/span&gt;
    &lt;span class="ident"&gt;render&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Aby uaktywni&#263; Haml nale&#380;y w pliku config/merb_init.rb dopisa&#263; na ko&#324;cu&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="constant"&gt;Merb&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Template&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Haml&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Warto te&#380; doinstalowa&#263; gemy:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;gem install -y merb_helpers merb_has_rails_plugins ruby-debug&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;i doda&#263; je do config/dependencies.rb&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;dependency&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;merb_helpers&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;
&lt;span class="ident"&gt;dependency&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;merb_has_rails_plugins&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;
&lt;span class="ident"&gt;dependency&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;ruby-debug&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Dzi&#281;ki temu b&#281;dziemy mieli dost&#281;pnych troch&#281; dodatkowych helper&#243;w  z Rails. Za&#347; gem ruby-debug umo&#380;liwia nam wpisanie w dowolnym miejscu komendy 
debugger przerywaj&#261;cej prac&#281; przegl&#261;darki i kieruj&#261;cej wykonanie kodu do konsoli. Po jej zako&#324;czeniu przegl&#261;darka wznawia obs&#322;ug&#281; requestu. Dzia&#322;a to tu tak jak w Rails. Mo&#380;na interaktywnie sobie operowa&#263; na &#380;ywym kodzie. Warto te&#380; wiedzie&#263;, &#380;e w Merb wszystkie pluginy s&#261; po prostu gemami. U&#322;atwia to zarz&#261;dzanie ich wersjami.&lt;/p&gt;


	&lt;p&gt;Plik widoku jest identyczny jak w wy&#380;ej dla Railsow wi&#281;c nie b&#281;d&#281; podawa&#322; jeszcze raz jego tre&#347;ci.&lt;/p&gt;


	&lt;p&gt;Odpalamy serwer za pomoc&#261; komendy &lt;em&gt;merb&lt;/em&gt; i na stronie http://localhost:4000/home podziwiamy wynik. :) Komenda merb&amp;#8212;help wy&#347;wietli wszystkie, dost&#281;pne opcje.&lt;/p&gt;


	&lt;h3&gt;Pylons&lt;/h3&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;paster controller home
# =&amp;gt; pylons_app/controllers/home.py&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Plik kontrolera (pylons_app/controllers/home.py):&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="ident"&gt;logging&lt;/span&gt;
&lt;span class="ident"&gt;from&lt;/span&gt; &lt;span class="ident"&gt;pylons_app&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;lib&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;base&lt;/span&gt; &lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="punct"&gt;*&lt;/span&gt;
&lt;span class="ident"&gt;log&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;logging&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;getLogger&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;__name__&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
&lt;span class="ident"&gt;from&lt;/span&gt; &lt;span class="ident"&gt;pylons_app&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;model&lt;/span&gt; &lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="constant"&gt;Session&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="constant"&gt;User&lt;/span&gt;

&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;HomeController(BaseController):&lt;/span&gt;
    &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;index&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;):&lt;/span&gt;
        &lt;span class="ident"&gt;user_query&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Session&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;query&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;User&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
        &lt;span class="ident"&gt;c&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;user&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;user_query&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;filter&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;User&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;name&lt;/span&gt; &lt;span class="punct"&gt;==&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;Jarek&lt;/span&gt;&lt;span class="punct"&gt;').&lt;/span&gt;&lt;span class="ident"&gt;one&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt;
        &lt;span class="keyword"&gt;return&lt;/span&gt; &lt;span class="ident"&gt;render&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;/home/index.mako&lt;/span&gt;&lt;span class="punct"&gt;')&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Plik widoku (pylons_app/templates/home/index.mako):&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_mako "&gt;U&#380;ytkownik ${c.user.name} posiada post(y)
&amp;lt;ul&amp;gt;
  % for post in c.user.posts:
    &amp;lt;li&amp;gt;${post.title}&amp;lt;/li&amp;gt;
  % endfor
&amp;lt;/ul&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Odpalamy serwer za pomoc&#261;&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;paster serve development.ini --reload&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Pylons nie posiada tryb&#243;w pracy tak jak Rails czy Merb. Wielow&#261;tkowy serwer &lt;span class="caps"&gt;HTTP&lt;/span&gt; (paster) musi dosta&#263; odpowiedni plik konfiguracyjny. Daje to w sumie wi&#281;cej mo&#380;liwo&#347;ci, bo mo&#380;na izolowa&#263; sobie r&#243;&#380;ne konfiguracje du&#380;o bardziej ni&#380; prosty podzia&#322; na tryb produkcyjny i rozwojowy.&lt;/p&gt;


	&lt;h2&gt;Podsumowanie.&lt;/h2&gt;


	&lt;p&gt;Rails jest bardzo bogato wyposa&#380;ony w r&#243;&#380;ne helpery, posiada dobr&#261; literatur&#281;, ksi&#261;&#380;ki itd. Jest te&#380; bardzo &#322;atwy do nauki i dosy&#263; intuicyjny. Je&#347;li chodzi o prototypowanie, to jest prawie nie do pobicia. Niestety, mo&#380;na si&#281; przyczepi&#263; do jako&#347;ci implementacji wewn&#281;trznej jak i do niekt&#243;rych &lt;a href="http://blog.zabiello.com/articles/2007/12/13/slabosci-active-record"&gt;b&#322;&#281;d&#243;w projektowych w Active Record&lt;/a&gt;. My&#347;l&#281;, &#380;e Railsom wyr&#243;s&#322; bardzzo gro&#378;ny konkurent w postaci Merba. Jest lepiej zorganizowany, sp&#243;jniejszy i szybszy. Jest te&#380; tak samo prosty i intuicyjny. Czy warto si&#281; przesiada&#263;? Wg mnie &amp;#8211; warto. Je&#347;li za&#347; chodzi o &lt;span class="caps"&gt;ORM&lt;/span&gt;, to Sequel jest pod wieloma wzgl&#281;dami lepszym projektem od Active Record. Tu mo&#380;e tego nie eksponowa&#322;em, ale Sequel pozwala na obiektowe budowanie znacznie bardziej skomplikowanych zapyta&#324; ni&#380; to potrafi Active Record czy DataMapper. Po przyk&#322;ady kodu Sequela odsy&#322;am do jego &lt;a href="http://code.google.com/p/ruby-sequel/"&gt;strony domowej&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;Co z Pylons? Korzysta z pot&#281;&#380;nego &lt;span class="caps"&gt;ORM&lt;/span&gt;&amp;#8217;a i pot&#281;&#380;nych szablon&#243;w. Ma pe&#322;n&#261; obs&#322;ug&#281; Unicode, szablony Mako natywnie pracuj&#261; na obiektach unikodowych (nie myli&#263; ze stringami utf8). Mako maj&#261; dziedziczenie, pot&#281;&#380;ny, elastyczny cache i s&#261; bardzo &amp;#8220;pythonic&amp;#8221; w swym podej&#347;ciu do budowania modu&#322;&#243;w czy custom tag&#243;w. Niestety Pylons w ca&#322;o&#347;ci wymaga troch&#281; wi&#281;cej wiedzy i umiej&#281;tno&#347;ci aby go ustawi&#263; do pracy. Rails i Merb s&#261; tu znacznie prostsze. Dzi&#281;ki za&#347;  Merb przepa&#347;&#263; mi&#281;dzy wydajno&#347;ci&#261; i mo&#380;liwo&#347;ciami pythonowego Pylonso a frameworkami Rubiego mocno si&#281; zmniejszyla. Ci, co czepiali si&#281; wcze&#347;niej wydajno&#347;ci Rails nie maj&#261; teraz specjalnie na co narzeka&#263;. Ci co narzekali na ograniczenia Active Record, nie maj&#261; wym&#243;wki w zetkni&#281;ciu z Sequelem. No chyba, &#380;e kto&#347; nie chce si&#281; uczy&#263; Rubiego, jego sprawa. Ja jednak uwa&#380;am, &#380;e Ruby to pi&#281;kny j&#281;zyk i bardzo przyjemnie si&#281; w nim pisze. A prostota Merba w por&#243;wnaniu z Pylons jest (szczeg&#243;lnie dla os&#243;b zaczynaj&#261;cych prac&#281;) &amp;#8211; powalaj&#261;ca.&lt;/p&gt;


	&lt;p&gt;Celem tego tekstu by&#322;o pom&#243;c osobom w pocz&#261;tkowej fazie konfiguracji Pylons oraz Merb. Mam nadziej&#281;, &#380;e by&#322; pomocny i dalej ju&#380; ka&#380;dy sobie sam da rad&#281;. Je&#347;li chodzi o dodatkow&#261; pomoc, to warto zajrze&#263; na &lt;span class="caps"&gt;IRC&lt;/span&gt;. Na serwerze freeenode istniej&#261; kana&#322;y: #pylons, #merb, #sequel, #datamapper, #rubyonrails oraz  nasze polskie #rubyonrails.pl i #python-pl. S&#261; te&#380; polskie grupy dyskusyjne w Usenecie: news://pl.comp.lang.python i news://pl.comp.lang.ruby.&lt;/p&gt;


&lt;hr /&gt;

	&lt;p&gt;Kod &#378;r&#243;d&#322;owy z powy&#380;szymi przyk&#322;adami &lt;a href="http://blog.zabiello.com/files/szybki-start.zip"&gt;mo&#380;na pobra&#263; st&#261;d&lt;/a&gt;&lt;/p&gt;</description>
      <pubDate>Sun, 16 Dec 2007 07:31:00 +0100</pubDate>
      <guid isPermaLink="false">urn:uuid:2a1dd95d-df5f-466d-bce9-87eb2b231833</guid>
      <author>Jaros&#322;aw Zabie&#322;&#322;o</author>
      <link>http://blog.zabiello.com/articles/2007/12/16/howto-rails-merb-pylons</link>
      <category>rails</category>
      <category>merb</category>
      <category>pylons</category>
      <category>sqlalchemy</category>
      <category>mako</category>
      <category>sequel</category>
      <category>activerecord</category>
      <category>ruby</category>
      <category>python</category>
    </item>
    <item>
      <title>Sequel vs Active Record. Cz&#281;&#347;&#263; 1 - s&#322;abo&#347;ci AR.</title>
      <description>&lt;p&gt;Gdy framework Ruby on Rails (dalej: RoR lub Rails) rozpoczyna&#322; swoj&#261; b&#322;yskotliw&#261; karier&#281;, zachwyca&#322; wszystkich prostot&#261; i elegancj&#261; konstrukcji. Jednym z fundamentalnych modu&#322;&#243;w Rails&#243;w jest Active Record, biblioteka realizuj&#261;ca symulacj&#281; wirtualnej bazy obiektowej, pozwalaj&#261;c&#261; na prac&#281; z relacyjnymi bazami danych za pomoc&#261; obiekt&#243;w j&#281;zyka Ruby. Active Record (dalej AR) nie unikn&#261;&#322; jednak kilku potkni&#281;&#263; projektowych.&lt;/p&gt;


	&lt;h3&gt;Brak parametryzowanych zapyta&#324; &lt;span class="caps"&gt;SQL&lt;/span&gt;&lt;/h3&gt;


	&lt;p&gt;Kompletnie nie rozumiem po co Active Record m&#281;czy si&#281; z budowaniem ca&#322;ej kwerendy &lt;span class="caps"&gt;SQL&lt;/span&gt;. Po co te&#380; jego tworcy trac&#261; czas na walk&#281; z analiz&#261; i odpowiednim escape&amp;#8217;owaniem znak&#243;w w danych przekazywanych do zapytania. Przecie&#380; &lt;a href="http://tmtm.org/en/mysql/ruby/"&gt;sterownik MySQL do Rubiego&lt;/a&gt; bez problemu to wszystko zrobi na nich! Ma&#322;o tego, u&#380;ywanie parametryzowanych zapyta&#324; &lt;span class="caps"&gt;SQL&lt;/span&gt; jest szybsze ni&#380; samodzielne budowanie ca&#322;ego stringa i wykonywanie na nim kwerendy.&lt;/p&gt;


	&lt;h3&gt;Brak iterator&#243;w&lt;/h3&gt;


	&lt;p&gt;Inn&#261; tajemnic&#261; developer&#243;w AR jest brak korzystania z iterator&#243;w. Zamiast tego AR, z uporem godnym lepszej sprawy, przepycha przez pami&#281;&#263; ca&#322;&#261; list&#281; obiekt&#243;w Rubiego. Im pobieramy wi&#281;cej rekord&#243;w z bazy tym wi&#281;cej obiekt&#243;w musimy przes&#322;a&#263; do pami&#281;ci (bo ka&#380;demu rekordowi odpowiada jeden egzemplarz klasy Active Record). AR wrzuca wi&#281;c &lt;strong&gt;wszystkie&lt;/strong&gt; obiekty &lt;span class="caps"&gt;ORM&lt;/span&gt; do pami&#281;ci. Troch&#281; to bez sensu, bo bazy danych s&#261; optymalizowane na pobieranie rekord&#243;w ma&#322;ymi porcjami. Grupowane pobieranie/wk&#322;adanie rekord&#243;w potrafi by&#263; nawet o dwa rz&#281;dy wielko&#347;ci szybsze. Gdyby &lt;span class="caps"&gt;DHH&lt;/span&gt; i koledzy popatrzyli dok&#322;adniej na standard &lt;a href="http://www.python.org/dev/peps/pep-0249/"&gt;&lt;span class="caps"&gt;PEP249&lt;/span&gt;&lt;/a&gt; Pythona a nie na chaotyczne praktyki rodem z &lt;span class="caps"&gt;PHP&lt;/span&gt;, to by takiego b&#322;&#281;du nie pope&#322;nili.&lt;/p&gt;


	&lt;h3&gt;Domy&#347;lne &lt;span class="caps"&gt;SELECT&lt;/span&gt; * i b&#322;&#261;d w :include&lt;/h3&gt;


	&lt;p&gt;Gdy AR wykonuje zapytanie komend&#281; Model.find(:all) to domy&#347;lnie wykonuje &amp;#8220;SELECT *...&amp;#8221; Nie by&#322;oby z tym problemu gdyby nie to, &#380;e MySQL nie potrafi indeksowa&#263; p&#243;&#322; typu &lt;span class="caps"&gt;TEXT&lt;/span&gt;/BLOB. Pobieranie &amp;#8220;hurtem&amp;#8221; wszystkich kolumn z kt&#243;rych jedna jest tego typu, dramatycznie spowalnia baz&#281; danych.&lt;/p&gt;


	&lt;p&gt;No dobrze, kto&#347; powie, &#380;e mo&#380;na zawsze u&#380;y&#263; opcji :select i wybra&#263; sobie pola jakie chcemy. Niestety to si&#281; sypie, gdy chcemy u&#380;y&#263; opcji :include aby uzyska&#263; &lt;span class="caps"&gt;LEFT OUTER JOIN&lt;/span&gt;. U&#380;ycie opcji :include anuluje bowiem efekt dzia&#322;ania opcji :select. (Aby to obej&#347;&#263; trzeba zast&#261;pi&#263; opcj&#281; :include opcj&#261; :joins i wklepa&#263; r&#281;cznie ca&#322;y fragment &lt;span class="caps"&gt;SQL&lt;/span&gt;. Opcja :joins nie koliduje z :select).&lt;/p&gt;


	&lt;h3&gt;Niesp&#243;jno&#347;&#263; sk&#322;adni :include i :joins.&lt;/h3&gt;


	&lt;p&gt;To mo&#380;e ma&#322;a sprawa, ale razi. Dlaczego :include pozwala na stosowanie &#322;adnego zapisy :include =&amp;gt; [:tabela1, :tabela2] a :joins przyjmuje tylko warto&#347;&#263; typu String, tj. czysty &lt;span class="caps"&gt;SQL&lt;/span&gt;?&lt;/p&gt;


	&lt;h3&gt;Aktualizacja jednej kolumny to aktualizacja wszystkich kolumn rekordu.&lt;/h3&gt;


	&lt;p&gt;To ju&#380; jest bardziej denerwuj&#261;ce. Chcemy zmieni&#263; fragment rekordu a AR serwuje nam update na wszystkich kolumnach. Nie ma jak to obej&#347;&#263; bez uciekania si&#281; do odpalenia czystego &lt;span class="caps"&gt;SQL&lt;/span&gt;&amp;#8217;a. Ca&#322;e szcz&#281;&#347;cie &#380;e AR na to pozwala.&lt;/p&gt;


	&lt;h3&gt;Brak obs&#322;ugi z&#322;o&#380;onych kluczy obcych&lt;/h3&gt;


	&lt;p&gt;AR domy&#347;lnie w og&#243;le nie obs&#322;uguje z&#322;o&#380;onych kluczy obcych (Sympatycy pythonowego Django nie maj&#261; tu te&#380; powodu do dumy, bo ich &lt;span class="caps"&gt;ORM&lt;/span&gt; r&#243;wnie&#380; tego nie potrafi). Sytuacj&#281; troch&#281; ratuje gem/plugin composite_primary_keys ale jak to z pluginami w Rails bywa, im ich mniej tym lepiej. No chyba, &#380;e kto&#347; sam prosi si&#281; o k&#322;opoty. Z jako&#347;ci&#261; plugin&#243;w jest r&#243;&#380;nie i trzeba ostro&#380;nie je dobiera&#263;.&lt;/p&gt;


	&lt;h3&gt;Brak krokowego budowania warunk&#243;w&lt;/h3&gt;


	&lt;p&gt;To jest jedna z bardziej denerwuj&#261;cych rzeczy. AR gromadzi warunki w warto&#347;ci do klucza/opcji :conditions. Mo&#380;e on przyjmowa&#263; warto&#347;&#263; typu String, Array lub Hash ale tylko jedn&#261; naraz i tylko raz. Je&#347;li chcemy zbudowa&#263; jaki&#347; bardziej z&#322;o&#380;ony warunek, to musimy skleja&#263; sobie r&#281;cznie kwerend&#281; i uwa&#380;a&#263; aby sobie przypadkiem nie strzeli&#263; jakim&#347; przypadkowym sql-injection w stop&#281;.&lt;/p&gt;


	&lt;p&gt;Nie wiem czy jest nadzieja na szybk&#261; popraw&#281; jako&#347;ci implementacji Active Record, bo mam wra&#380;enie &#380;e developerzy i kontrybutorzy skupieni wok&#243;&#322; tego frameworka wol&#261; goni&#263; za nowymi funkcjami zamiast zatrzyma&#263; si&#281; i dopracowa&#263; to, co ju&#380; stworzono. Na szcz&#281;&#347;cie nie trzeba czeka&#263;. Active Record doczeka&#322; si&#281; godnych nast&#281;pc&#243;w. Najbardziej znacz&#261;ce s&#261; dwa: &lt;a href="http://datamapper.org/"&gt;DataMapper&lt;/a&gt; i &lt;a href="http://code.google.com/p/ruby-sequel/"&gt;Sequel&lt;/a&gt;. Szczeg&#243;lnie godny uwagi jest Sequel. Ale o tym w nast&#281;pnej cz&#281;&#347;ci.&lt;/p&gt;


	&lt;p&gt;Zobacz &lt;a href="http://blog.zabiello.com/articles/2007/12/21/integracja-rails-z-sequelem"&gt;Sequel vs Active Record. Cz&#281;&#347;&#263; 2 &amp;#8211; integracja Rails z Sequelem&lt;/a&gt;&lt;/p&gt;</description>
      <pubDate>Thu, 13 Dec 2007 00:37:00 +0100</pubDate>
      <guid isPermaLink="false">urn:uuid:9ab994be-9bca-4c3d-ae20-6fa8fee44696</guid>
      <author>Jaros&#322;aw Zabie&#322;&#322;o</author>
      <link>http://blog.zabiello.com/articles/2007/12/13/slabosci-active-record</link>
      <category>rails</category>
      <category>ruby</category>
      <category>orm</category>
      <category>activerecord</category>
    </item>
    <item>
      <title>Ulepszony String i sprawa parametr&#243;w</title>
      <description>&lt;p&gt;Ruby posiada bardzo bogate mo&#380;liwo&#347;ci przetwarzania tekstu. Zasugerowany sk&#322;adni&#261; Active Record i wcze&#347;niejszym do&#347;wiadczeniem z Pythonem troch&#281; si&#281; zdziwi&#322;em, &#380;e Matz nie zaimplementowa&#322; przekazywania hasza do operatora &lt;code&gt;%&lt;/code&gt;.&lt;/p&gt;


	&lt;h3&gt;Parametry w Active Record.&lt;/h3&gt;


	&lt;p&gt;Co prawda &lt;a href="http://ar.rubyonrails.org/"&gt;Active Record&lt;/a&gt; nie mia&#322; mo&#380;e nigdy ambicji kompletnego pozbycia si&#281; j&#281;zyka &lt;span class="caps"&gt;SQL&lt;/span&gt;, ale na tle takiego &lt;a href="http://sqlalchemy.org"&gt;SQLAlchemy&lt;/a&gt; wypada znacznie mniej obiektowo&lt;sup&gt;&lt;a href="#fn1"&gt;1&lt;/a&gt;&lt;/sup&gt;. Wida&#263; to po sposobie budowania warunk&#243;w. Active Record umo&#380;liwia przekazywanie parametr&#243;w do warunk&#243;w na trzy podstawowe&lt;sup&gt;&lt;a href="#fn2"&gt;2&lt;/a&gt;&lt;/sup&gt; sposoby.&lt;/p&gt;


	&lt;h4&gt;&amp;#8220;Chamskie&amp;#8221; budowanie stringu &lt;span class="caps"&gt;SQL&lt;/span&gt;&lt;/h4&gt;


	&lt;p&gt;Ta metoda jest najbardziej popularna u wszelkiej ma&#347;ci lamer&#243;w i os&#243;b pocz&#261;tkuj&#261;cych. Jest bardzo powszechna w&#347;r&#243;d pehapowc&#243;w, kt&#243;rzy niedawno zacz&#281;li bawi&#263; si&#281; Railsami. Przyk&#322;adowy kod tego typu wygl&#261;da&#322;by mniej wi&#281;cej tak:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;user&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;passwd&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;params&lt;/span&gt;&lt;span class="punct"&gt;['&lt;/span&gt;&lt;span class="string"&gt;user&lt;/span&gt;&lt;span class="punct"&gt;'],&lt;/span&gt; &lt;span class="ident"&gt;params&lt;/span&gt;&lt;span class="punct"&gt;['&lt;/span&gt;&lt;span class="string"&gt;passwd&lt;/span&gt;&lt;span class="punct"&gt;']&lt;/span&gt;
&lt;span class="constant"&gt;Model&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;find&lt;/span&gt; &lt;span class="symbol"&gt;:all&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:conditions&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;user='&lt;span class="expr"&gt;#{user}&lt;/span&gt;' AND login='&lt;span class="expr"&gt;#{passwd}&lt;/span&gt;'&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Taka &amp;#8220;radosna tfurczo&#347;&#263;&amp;#8221; jest z ca&#322;&#261; pewno&#347;ci&#261; zaproszeniem do klasycznego ataku &lt;a href="http://pl.wikipedia.org/wiki/SQL_Injection"&gt;&lt;span class="caps"&gt;SQL&lt;/span&gt; Injection&lt;/a&gt;. Rails posiada co prawda funkcj&#281; &lt;code&gt;sanitize_sql()&lt;/code&gt; kt&#243;ra pacyfikuje niebezpieczne znaki w kwerendzie &lt;span class="caps"&gt;SQL&lt;/span&gt;, ale mo&#380;na o niej zapomnie&#263;, a kod staje si&#281; po prostu brzydki. Zatem tego typu praktyce m&#243;wimy stanowcze: fuj!&lt;/p&gt;


	&lt;p&gt;Prawie wszystkie relacyjne bazy pozwalaj&#261; na budowanie parametryzowanego &lt;span class="caps"&gt;SQL&lt;/span&gt;&amp;#8217;a. Na tym bazuj&#261; dwie kolejne metody.&lt;/p&gt;


	&lt;h4&gt;Przekazywanie listy.&lt;/h4&gt;


	&lt;p&gt;Warunek &lt;code&gt;:conditions&lt;/code&gt; mo&#380;e przyjmowa&#263; zar&#243;wno String jak i Array. W tym drugim wypadku dostajemy za darmo kod uodporniony na atak &lt;span class="caps"&gt;SQL&lt;/span&gt; Injection. Nie trzeba pami&#281;ta&#263; o tym czy dane zawieraj&#261; jakie&#347; niebezpieczne znaki. Nie trzeba te&#380; zastanawia&#263; si&#281; czy przekazywny parametr jest liczb&#261;, czy stringiem (wymagaj&#261;cym apostrof&#243;w w kodzie &lt;span class="caps"&gt;SQL&lt;/span&gt;). Kod jest wi&#281;c i prostszy i bezpieczniejszy.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;user&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;passwd&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;params&lt;/span&gt;&lt;span class="punct"&gt;['&lt;/span&gt;&lt;span class="string"&gt;user&lt;/span&gt;&lt;span class="punct"&gt;'],&lt;/span&gt; &lt;span class="ident"&gt;params&lt;/span&gt;&lt;span class="punct"&gt;['&lt;/span&gt;&lt;span class="string"&gt;passwd&lt;/span&gt;&lt;span class="punct"&gt;']&lt;/span&gt;
&lt;span class="constant"&gt;Model&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;find&lt;/span&gt; &lt;span class="symbol"&gt;:all&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:conditions&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;[&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;user=? AND login=?&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt; &lt;span class="ident"&gt;user&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;passwd&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;h4&gt;Przekazywanie hasza.&lt;/h4&gt;


	&lt;p&gt;Przekazywanie listy ma pewn&#261; wad&#281;: trzeba pami&#281;ta&#263; o kolejno&#347;ci parametr&#243;w. Tak&#380;e zawiera niepotrzebn&#261; redundancj&#281; w wypadku kiedy jaki&#347; parametr musi si&#281; powtarza&#263;. Dlatego Active Record umo&#380;liwia korzystanie ze sk&#322;adni inspirowanej baz&#261; Oracle.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;user&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;passwd&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;params&lt;/span&gt;&lt;span class="punct"&gt;['&lt;/span&gt;&lt;span class="string"&gt;user&lt;/span&gt;&lt;span class="punct"&gt;'],&lt;/span&gt; &lt;span class="ident"&gt;params&lt;/span&gt;&lt;span class="punct"&gt;['&lt;/span&gt;&lt;span class="string"&gt;passwd&lt;/span&gt;&lt;span class="punct"&gt;']&lt;/span&gt;
&lt;span class="constant"&gt;Model&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;find&lt;/span&gt; &lt;span class="symbol"&gt;:all&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:conditions&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;[&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;user=:user AND login=:login&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt;&lt;span class="symbol"&gt;:user&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ident"&gt;user&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:passwd&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ident"&gt;passwd&lt;/span&gt;&lt;span class="punct"&gt;}]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;lub jeszcze kr&#243;cej:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="constant"&gt;Model&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;find&lt;/span&gt; &lt;span class="symbol"&gt;:all&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:conditions&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;[&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;user=:user AND login=:login&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt;&lt;span class="ident"&gt;params&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;h3&gt;Parametry do stringa.&lt;/h3&gt;


	&lt;p&gt;Po tym wst&#281;pie, pora na (niemi&#322;&#261;) niespodziank&#281; jak&#261; spotka&#322;em w implementacji Rubiego. Generalnie Ruby posiada bardzo bogate mo&#380;liwo&#347;ci przetwarzania tekstu. Podobnie jak Python, posiada te&#380; skr&#243;con&#261; form&#281; funkcji &lt;code&gt;sprintf&lt;/code&gt; realizowan&#261; za pomoc&#261;  operatora &lt;code&gt;%&lt;/code&gt;.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;%s can use %s.&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;%&lt;/span&gt; &lt;span class="punct"&gt;['&lt;/span&gt;&lt;span class="string"&gt;Ruby&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;list of parameters&lt;/span&gt;&lt;span class="punct"&gt;']&lt;/span&gt;
&lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Ruby can use list of parameters.&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Python jednak&#380;e pozwala tak&#380;e na u&#380;ywanie s&#322;ownik&#243;w.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;params&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;{'&lt;/span&gt;&lt;span class="string"&gt;lang&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="symbol"&gt;:'&lt;/span&gt;&lt;span class="symbol"&gt;Python&lt;/span&gt;&lt;span class="symbol"&gt;'&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;what&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="symbol"&gt;:'&lt;/span&gt;&lt;span class="symbol"&gt;a dictionary&lt;/span&gt;&lt;span class="symbol"&gt;'&lt;/span&gt;&lt;span class="punct"&gt;}&lt;/span&gt;
&lt;span class="ident"&gt;print&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;%(lang)s can also use %(what)s.&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;%&lt;/span&gt; &lt;span class="ident"&gt;params&lt;/span&gt;
&lt;span class="constant"&gt;Python&lt;/span&gt; &lt;span class="ident"&gt;can&lt;/span&gt; &lt;span class="ident"&gt;also&lt;/span&gt; &lt;span class="ident"&gt;use&lt;/span&gt; &lt;span class="ident"&gt;a&lt;/span&gt; &lt;span class="ident"&gt;dictionary&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Troch&#281; mnie zdziwi&#322;o, &#380;e Ruby nie posiada odpowiednika tej funkcjonalno&#347;ci&amp;#8230;. Na szcz&#281;&#347;cie, dzi&#281;ki otwartym klasom, &lt;a href="http://en.wikipedia.org/wiki/Monkey_patch"&gt;monkey patching&lt;/a&gt; w przypadku Rubiego nabiera zupe&#322;nie innego wymiaru. Nic nie stoi na przeszkodzie aby ulepszy&#263; standardowy obiekt String.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;String&lt;/span&gt;  
  &lt;span class="ident"&gt;alias_method&lt;/span&gt; &lt;span class="symbol"&gt;:old_percent&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;:%&lt;/span&gt;
  &lt;span class="comment"&gt;# Template strings. &lt;/span&gt;
  &lt;span class="comment"&gt;# Inspired by Python %(key)s and $key syntax.&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;%&lt;/span&gt; &lt;span class="ident"&gt;var&lt;/span&gt;
    &lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="ident"&gt;var&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;==&lt;/span&gt; &lt;span class="ident"&gt;Hash&lt;/span&gt;
      &lt;span class="ident"&gt;var&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;each_pair&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;key&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;value&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;
        &lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="ident"&gt;key&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;to_s&lt;/span&gt; &lt;span class="punct"&gt;=~&lt;/span&gt; &lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="regex"&gt;^[a-z]+$&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;
          &lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;gsub!&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;$(&lt;span class="expr"&gt;#{key}&lt;/span&gt;)&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt; &lt;span class="ident"&gt;value&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;to_s&lt;/span&gt;
          &lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;gsub!&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;$&lt;span class="expr"&gt;#{key}&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt; &lt;span class="ident"&gt;value&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;to_s&lt;/span&gt;
        &lt;span class="keyword"&gt;end&lt;/span&gt;
      &lt;span class="keyword"&gt;end&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;    
    &lt;span class="ident"&gt;old_percent&lt;/span&gt; &lt;span class="ident"&gt;var&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;

&lt;span class="ident"&gt;hash&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt;&lt;span class="symbol"&gt;:lang&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;Ruby&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="symbol"&gt;:what&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;a hash&lt;/span&gt;&lt;span class="punct"&gt;'}&lt;/span&gt;
&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Now $lang can also use $what :)&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;%&lt;/span&gt; &lt;span class="ident"&gt;hash&lt;/span&gt;
&lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Now Ruby can also use a hash :)&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;I jak tu nie powiedzie&#263;, &#380;e Ruby jest pi&#281;kny? :)&lt;/p&gt;


&lt;hr size="1" width="30%" align="left" /&gt;

	&lt;p id="fn1"&gt;&lt;sup&gt;1&lt;/sup&gt; Active Record jest te&#380; mniej zaawansowany ni&#380; np. SQLAlchemy. Funkcjonalno&#347;&#263; Active Record jest mo&#380;e i &#347;wietna, ale jego implementacja w wielu punktach jest z pewno&#347;ci&#261; niedojrza&#322;a. Np. nie mam poj&#281;cia dlaczego Active Record zwraca list&#281; obiekt&#243;w zamiast generator, to pozwoli&#322;oby na wi&#281;ksze oszcz&#281;dno&#347;ci pami&#281;ci.&lt;/p&gt;


	&lt;p id="fn2"&gt;&lt;sup&gt;2&lt;/sup&gt; Bardziej obiektowe budowanie warunk&#243;w zapewniaj&#261; pluginy &lt;a href="http://agilewebdevelopment.com/plugins/ez_where"&gt;ez_where&lt;/a&gt; i &lt;a href="http://agilewebdevelopment.com/plugins/condition_builder"&gt;Condition Builder&lt;/a&gt;.&lt;/p&gt;</description>
      <pubDate>Fri, 29 Jun 2007 02:42:00 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:fbba7197-20e9-4c68-ba9b-f30633f57374</guid>
      <author>Jaros&#322;aw Zabie&#322;&#322;o</author>
      <link>http://blog.zabiello.com/articles/2007/06/29/improved-string</link>
      <category>ruby</category>
      <category>rails</category>
      <category>activerecord</category>
      <category>monkeypatching</category>
    </item>
    <item>
      <title>Ulepszanie funkcjonalno&#347;ci Active Record</title>
      <description>&lt;p&gt;&lt;a href="http://ar.rubyonrails.org/"&gt;Active Record&lt;/a&gt; to standardowy &lt;a href="http://en.wikipedia.org/wiki/Object-relational_mapping"&gt;&lt;span class="caps"&gt;ORM&lt;/span&gt;&lt;/a&gt; u&#380;ywany przez framework &lt;a href="http://rubyonrails.org"&gt;Rails&lt;/a&gt;. Zasadniczo jest dobrze zaprojektowany, prosty i wygodny. Nie trzeba &#380;mudnie definiowa&#263; ka&#380;dego pola w tabeli dla modelu, oraz mo&#380;na bez problemu podpina&#263; aplikacj&#281; do kilku r&#243;&#380;nych baz (czego np. nie ma &lt;a href="http://djangoproject.com"&gt;Django&lt;/a&gt;).&lt;/p&gt;


	&lt;h3&gt;Gdzie s&#261; te pola?&lt;/h3&gt;


	&lt;p&gt;Kwestia tego, czy w modelu definiowa&#263; pola czy nie, jest w zasadzie kontrowersyjna. Cho&#263; wad&#261; jest dodatkowy nak&#322;ad pracy zwi&#261;zany ze &#380;mudnym definiowaniem ka&#380;dego pola, to zalet&#261; jest to, &#380;e wystarczy spojrze&#263; na kod modelu, aby od razu wiedzie&#263; z jakimi polami mamy do czynienia. &lt;span class="caps"&gt;W AR&lt;/span&gt; ca&#322;a podstawowa definicja modelu sprowadza si&#281; (pomijam walidacje i relacje) do trywialnego zapisu:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Person&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;ActiveRecord&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Base&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Taki zapis zak&#322;ada, &#380;e istnieje tabela o nazwie people i posiada klucz g&#322;&#243;wny o nazwie id. Jest to zgodne z konwencjami jakie przyj&#281;to w Railsach i oczywi&#347;cie mo&#380;na to zmieni&#263; je&#347;li jest taka potrzeba.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Person&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;ActiveRecord&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Base&lt;/span&gt;
  &lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;table_name&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="symbol"&gt;:users&lt;/span&gt;
  &lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;primary_key&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="symbol"&gt;:user_id&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Jednak przy du&#380;ej ilo&#347;ci modeli nie zawsze b&#281;dziemy pami&#281;ta&#263; z jakimi polami w tabeli mamy do czynienia. Z pomoc&#261; przychodzi plugin &lt;a href="http://pragdave.pragprog.com/pragdave/2006/02/annotate_models.html"&gt;Annotate Models&lt;/a&gt;. Po zainstalowaniu za pomoc&#261; komendy (odpalanej w katalogu aplikacji Rails) mo&#380;emy troch&#281; poprawi&#263; definicj&#281; modelu.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;script&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;plugin&lt;/span&gt; &lt;span class="ident"&gt;install&lt;/span&gt; &lt;span class="ident"&gt;http&lt;/span&gt;&lt;span class="punct"&gt;:/&lt;/span&gt;&lt;span class="regex"&gt;&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;svn&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;pragprog&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;com&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="constant"&gt;Public&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;plugins&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;annotate_models&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Po odpaleniu komendy&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;rake&lt;/span&gt; &lt;span class="ident"&gt;annotate_models&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Ruby &amp;#8220;automagicznie&amp;#8221; przejrzy zawarto&#347;&#263; tabeli odpowiadaj&#261;cej ka&#380;demu modelowi &lt;span class="caps"&gt;ORM&lt;/span&gt; i doda odpowiednie komentarze do pocz&#261;tku pliku. Np.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="comment"&gt;# == Schema Information&lt;/span&gt;
&lt;span class="comment"&gt;#&lt;/span&gt;
&lt;span class="comment"&gt;# Table name: news&lt;/span&gt;
&lt;span class="comment"&gt;#&lt;/span&gt;
&lt;span class="comment"&gt;#  id         :integer(11)   not null, primary key&lt;/span&gt;
&lt;span class="comment"&gt;#  header     :text          &lt;/span&gt;
&lt;span class="comment"&gt;#  message    :text          &lt;/span&gt;
&lt;span class="comment"&gt;#  updated_at :timestamp     not null&lt;/span&gt;
&lt;span class="comment"&gt;#&lt;/span&gt;

&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;News&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;ActiveRecord&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Base&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;W efekcie mamy i prostot&#281; i potrzebn&#261; nam informacj&#281; w jednym miejscu.&lt;/p&gt;


	&lt;h3&gt;Nietypowe tabele &amp;#8211; z&#322;o&#380;one klucze g&#322;&#243;wne&lt;/h3&gt;


	&lt;p&gt;Nie jest tajemnic&#261;, &#380;e AR nie posiada wsparcia dla z&#322;o&#380;onych kluczy g&#322;&#243;wnych. Czy to znaczy, &#380;e Rails nie nadaje si&#281; do pracy z tabelami kt&#243;re takie klucze posiadaj&#261;? Nie. To, &#380;e AR nie posiada takiej mo&#380;liwo&#347;ci standardowo nic nie znaczy. Wystarczy doinstalowa&#263; &lt;a href="http://compositekeys.rubyforge.org/"&gt;Composite Primary Keys&lt;/a&gt; kt&#243;ry rozszerza standardowe mo&#380;liwo&#347;ci AR. Z do&#347;wiadczenia mog&#281; potwierdzi&#263;, &#380;e dzia&#322;a ca&#322;kiem dobrze. Jedyny problem jaki napotka&#322;em dotyczy&#322; tworzenia dynamicznego rusztowania (scaffolding) w modelu posiadaj&#261;cym z&#322;o&#380;one klucze g&#322;&#243;wne.&lt;/p&gt;


	&lt;h3&gt;ez_where &amp;#8211; bardziej obiektowe warunki wyszukiwania&lt;/h3&gt;


	&lt;p&gt;AR jest krytykowany za zbyt du&#380;&#261; ilo&#347;&#263; kodu &lt;span class="caps"&gt;SQL&lt;/span&gt; jaki trzeba u&#380;ywa&#263; w warunkach. Np.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;find_users&lt;/span&gt;
  &lt;span class="ident"&gt;find&lt;/span&gt; &lt;span class="symbol"&gt;:all&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; 
       &lt;span class="symbol"&gt;:conditions&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;[&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;name NOT LIKE ? AND rights IN(?)&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;kowalski&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;&lt;span class="number"&gt;4&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;&lt;span class="number"&gt;8&lt;/span&gt;&lt;span class="punct"&gt;]]&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Sytuacj&#281; poprawia plugin &lt;a href="http://agilewebdevelopment.com/plugins/ez_where"&gt;ez_where&lt;/a&gt;. Aby jednak stosowanie jego by&#322;o bardziej eleganckie, warto modyfikowa&#263; (otworzy&#263;) klas&#281; ActiveRecord:Base. Po dodaniu nast&#281;puj&#261;cego kodu do config/environment.rb:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;ActiveRecord::Base&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;self.orm_conditions&lt;/span&gt;&lt;span class="punct"&gt;(&amp;amp;&lt;/span&gt;&lt;span class="ident"&gt;block&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="constant"&gt;Caboose&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;EZ&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Condition&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;(&amp;amp;&lt;/span&gt;&lt;span class="ident"&gt;block&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;to_sql&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;mo&#380;na w modelu stosowa&#263; wygodniejszy zapis warunk&#243;w wyszukiwania.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;find_users&lt;/span&gt;
  &lt;span class="ident"&gt;find&lt;/span&gt; &lt;span class="symbol"&gt;:all&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; 
       &lt;span class="symbol"&gt;:conditions&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ident"&gt;orm_conditions&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;
         &lt;span class="ident"&gt;name!&lt;/span&gt; &lt;span class="punct"&gt;=~&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;kowalski&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;
         &lt;span class="ident"&gt;rights&lt;/span&gt; &lt;span class="punct"&gt;===&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;&lt;span class="number"&gt;4&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;&lt;span class="number"&gt;8&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt;
       &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;ez_where pozwala oczywi&#347;cie na bardziej skomplikowane konstrukcje. (Poza tym pluginem istnieje podobny, konkurencyjny &amp;#8211; &lt;a href="http://agilewebdevelopment.com/plugins/condition_builder"&gt;Condition Builder&lt;/a&gt;, kt&#243;rego mo&#380;na zintegrowa&#263; z AR w podobny spos&#243;b).&lt;/p&gt;


	&lt;h4&gt;Appendix 2007-07-04&lt;/h4&gt;


	&lt;p&gt;ez_where Ma ju&#380; zdefiniowan&#261; metod&#281; &lt;code&gt;c&lt;/code&gt;, wi&#281;c powy&#380;szy przyk&#322;ad mo&#380;na zapisa&#263;:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;find_users&lt;/span&gt;
  &lt;span class="ident"&gt;find&lt;/span&gt; &lt;span class="symbol"&gt;:all&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; 
       &lt;span class="symbol"&gt;:conditions&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ident"&gt;c&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;
         &lt;span class="ident"&gt;name!&lt;/span&gt; &lt;span class="punct"&gt;=~&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;kowalski&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;
         &lt;span class="ident"&gt;rights&lt;/span&gt; &lt;span class="punct"&gt;===&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;&lt;span class="number"&gt;4&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;&lt;span class="number"&gt;8&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt;
       &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;to_sql&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;To nie jest wszystko o co mo&#380;na rozszerzy&#263; AR. Istnieje ju&#380; ca&#322;kiem &lt;a href="http://agilewebdevelopment.com/plugins/category/2"&gt;imponuj&#261;ca liczba plugin&#243;w&lt;/a&gt; kt&#243;re s&#261; w stanie uzupe&#322;ni&#263; AR o funkcjonalno&#347;ci jakich standardowo nie posiada. Jest to zgodne z polityk&#261; jak&#261; tw&#243;rcy Rails maj&#261; w tej dziedzinie. Rdze&#324; Rails&#243;w powinien by&#263; prosty i funkcjonalny do wi&#281;kszo&#347;ci zastosowa&#324;. A dla os&#243;b potrzebuj&#261;cych dodatkowych mo&#380;liwo&#347;ci, przewidziano &lt;a href="http://agilewebdevelopment.com/plugins"&gt;mechanizm plugin&#243;w&lt;/a&gt;.&lt;/p&gt;</description>
      <pubDate>Sun, 24 Jun 2007 14:19:00 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:a22b4618-277e-4930-b55e-de7e78b58a34</guid>
      <author>Jaros&#322;aw Zabie&#322;&#322;o</author>
      <link>http://blog.zabiello.com/a