<?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: Elastyczno&#347;&#263; Rails&#243;w</title>
    <link>http://blog.zabiello.com/articles/2006/10/04/flexiblerails</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>moje notatki, linki, komentarze</description>
    <item>
      <title>Elastyczno&#347;&#263; Rails&#243;w</title>
      <description>&lt;p&gt;Wi&#281;kszo&#347;&#263; os&#243;b, kt&#243;re zetkn&#281;&#322;y si&#281; z frameworkiem Ruby on Rails zauwa&#380;y&#322;a, &#380;e domy&#347;lne ustawienia s&#261; tam tak dobrane, aby maksymalnie upro&#347;ci&#263; i zminimalizowa&#263; ilo&#347;&#263; r&#281;cznej pracy przy ustawieniach. Je&#347;li wi&#281;c kto&#347; trzyma si&#281; flozofii i konwencji nazw (np. dla tabel i ich p&#243;l) b&#281;dzie mia&#322; znacznie mniej dodatkowej roboty z konfiguracj&#261; frameworka do pracy. Typowa definicja modelu  wygl&#261;da&#263; mo&#380;e nawet tak prosto:&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="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Powy&#380;sza definicja zak&#322;ada, &#380;e tabela w bazie nosi nazw&#281; &amp;#8220;users&amp;#8221;, a jej primary key nazywa si&#281; &amp;#8220;id&amp;#8221;.  W przeciwie&#324;stwie do innych &lt;span class="caps"&gt;ORM&lt;/span&gt;&amp;#8217;&#243;w, railsowy ActiveRecord nie wymaga &#380;adnego wcze&#347;niejszego definiowania p&#243;l. Ruby bez problemu sam sobie wyciagnie wszystkie nazwy p&#243;l w spos&#243;b &lt;strong&gt;dynamiczny&lt;/strong&gt; wtedy, kiedy b&#281;dzie mu to potrzebne.&lt;/p&gt;


	&lt;h2&gt;Nietypowe struktury&lt;/h2&gt;


	&lt;p&gt;Niestety, nie zawsze jeste&#347;my w takiej komfortowej sytuacji, &#380;e mamy wp&#322;yw na nazewnictwo tabel i ich p&#243;l. Jednak to nie jest wi&#281;kszym problemem, bo Rails sobie z tym radzi r&#243;wnie prosto.&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;set_table_name&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;uzytkownicy&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;
  &lt;span class="ident"&gt;set_primary_key&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;IdUzytkownika&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;Jak wida&#263;, du&#380;o pracy nam nie przyby&#322;o. W tym wypadku musieli&#347;my tylko jawnie poda&#263; jak si&#281; nazywa nasza tabela i jak si&#281; nazywa jej klucz g&#322;&#243;wny.&lt;/p&gt;


	&lt;h2&gt;Korzystanie z wielu baz&lt;/h2&gt;


	&lt;p&gt;W momencie tworzenia projektu aplikacji RoR generowany jest automatycznie plik konfiguracyjny zawieraj&#261;cy po&#322;&#261;czenie do bazy danych. Przyk&#322;adowy plik config/database.yml mog&#322;by wygl&#261;da&#263; np. tak:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;default&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; &lt;span class="punct"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ident"&gt;defaults&lt;/span&gt;
  &lt;span class="ident"&gt;adapter&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; &lt;span class="ident"&gt;mysql&lt;/span&gt;
  &lt;span class="ident"&gt;host&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; &lt;span class="ident"&gt;localhost&lt;/span&gt;
  &lt;span class="ident"&gt;encoding&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; &lt;span class="ident"&gt;utf8&lt;/span&gt;
  &lt;span class="ident"&gt;username&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; &lt;span class="ident"&gt;jakis_login&lt;/span&gt;
  &lt;span class="ident"&gt;password&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; &lt;span class="ident"&gt;jakies_haslo&lt;/span&gt;

&lt;span class="ident"&gt;development&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt;
  &lt;span class="ident"&gt;database&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; &lt;span class="ident"&gt;bookstore_dev&lt;/span&gt;
  &lt;span class="punct"&gt;&amp;lt;&amp;lt;:&lt;/span&gt; &lt;span class="punct"&gt;*&lt;/span&gt;&lt;span class="ident"&gt;defaults&lt;/span&gt;

&lt;span class="ident"&gt;test&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt;
  &lt;span class="ident"&gt;database&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; &lt;span class="ident"&gt;bookstore_test&lt;/span&gt;
  &lt;span class="ident"&gt;port&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; &lt;span class="number"&gt;3307&lt;/span&gt;
  &lt;span class="punct"&gt;&amp;lt;&amp;lt;:&lt;/span&gt; &lt;span class="punct"&gt;*&lt;/span&gt;&lt;span class="ident"&gt;defaults&lt;/span&gt;

&lt;span class="ident"&gt;production&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt;
  &lt;span class="ident"&gt;database&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; &lt;span class="ident"&gt;bookstore&lt;/span&gt;
  &lt;span class="ident"&gt;socket&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; &lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="regex"&gt;var&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;run&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;mysqld&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;mysqld&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;sock&lt;/span&gt;
  &lt;span class="punct"&gt;&amp;lt;&amp;lt;:&lt;/span&gt; &lt;span class="punct"&gt;*&lt;/span&gt;&lt;span class="ident"&gt;defaults&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Co robi powy&#380;szy kod? Definiuje 3 bazy: produkcyjn&#261;, robocz&#261; i testow&#261;. (Ta ostatnia jest u&#380;ywana tylko do test&#243;w jednostkowych wi&#281;c nie powinno si&#281; tam wstawia&#263; &#380;adnych istotnych danych) W w/w konfiguracji zdecydowali&#347;my, &#380;e wszystkie bazy b&#281;d&#261; korzysta&#263; z MySQL &amp;gt;=4.1 z ustawionym wew. kodowaniem &lt;span class="caps"&gt;UTF&lt;/span&gt;-8 (zalecane). Baza produkcyjna dzia&#322;a&#263; b&#281;dzie na Linuksie, wi&#281;c zamiast portu &lt;span class="caps"&gt;TCP&lt;/span&gt;, podano uniksowy socket. Baza testowa dzia&#322;a na porcie 3307, a robocza na domy&#347;lnym (3306). G&#322;&#243;wna sekcja &amp;#8220;defaults&amp;#8221; jest wsp&#243;lna dla wszystkich trzech baz zgodnie z zasad&#261; &lt;span class="caps"&gt;DRY&lt;/span&gt; (Don&amp;#8217;t Repeat Yourself).&lt;/p&gt;


	&lt;p&gt;Za&#322;&#243;&#380;my jednak, &#380;e chcemy korzysta&#263; z dodatkowej bazy i chcemy aby z niej korzysta&#322;y niekt&#243;re modele. &#379;aden problem. Do pliku dopisujemy tylko dodatkow&#261; definicj&#281; po&#322;&#261;czenia do innej bazy:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;other&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt;
  &lt;span class="ident"&gt;adapter&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; &lt;span class="ident"&gt;mysql&lt;/span&gt;
  &lt;span class="ident"&gt;host&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; &lt;span class="number"&gt;192.168&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="number"&gt;0.123&lt;/span&gt;
  &lt;span class="ident"&gt;database&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; &lt;span class="ident"&gt;customers&lt;/span&gt;
  &lt;span class="punct"&gt;&amp;lt;&amp;lt;:&lt;/span&gt; &lt;span class="punct"&gt;*&lt;/span&gt;&lt;span class="ident"&gt;defaults&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Jak wida&#263;, mo&#380;emy t&#261; metod&#261; tworzy&#263; aplikacj&#281; korzystaj&#261;c&#261; z rozproszonych baz. (W tym wypadku baza customers le&#380;y na zupe&#322;nie innym serwerze, ale korzysta z tego samego usera i has&#322;a.)&lt;/p&gt;


	&lt;p&gt;No dobrze, ale jak modele maj&#261; rozpozna&#263; z jakiego po&#322;&#261;czenia korzystaj&#261;? To te&#380; prosta sprawa. Domy&#347;lnym po&#322;&#261;czeniem jest to, co zdefiniowano w sekcji domy&#347;lnej. Jedynie modele, kt&#243;re korzystaj&#261; z innego po&#322;&#261;czenia, musz&#261; to mie&#263; jawnie zadeklarowane w definicji, np.&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;Client&lt;/span&gt;
  &lt;span class="ident"&gt;establish_connection&lt;/span&gt; &lt;span class="symbol"&gt;:other&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Model Client oraz  wszystkie modele utworzone z niego na drodze dziedziczenia, b&#281;d&#261; korzysta&#263; z innego po&#322;&#261;czenia ni&#380; domy&#347;lne.&lt;/p&gt;


	&lt;p&gt;&lt;span class="caps"&gt;BTW&lt;/span&gt;, to jedna z bardziej brakuj&#261;cych mi cech we frameworku &lt;a href="http://djangoproject.com"&gt;Django&lt;/a&gt; (&lt;a href="http://pylonshq.com"&gt;Pylons&lt;/a&gt; nie ma z tym &#380;adnego problemu). Mam nadziej&#281;, &#380;e wkr&#243;tce to poprawi&#261; i w &lt;a href="http://djangoproject.com"&gt;Django&lt;/a&gt; b&#281;dzie mo&#380;na bez problemu korzysta&#263; z wielu baz.&lt;/p&gt;


	&lt;h2&gt;Wspolne modele dla wielu aplikacji Rails&lt;/h2&gt;


	&lt;p&gt;W tym scenariuszu mamy za zadanie stworzy&#263; szereg aplikacji webowych korzystaj&#261;cych z oddzielnych baz o &lt;em&gt;tej samej&lt;/em&gt; strukturze tabel. Chcemy unikn&#261;&#263; powielania kodu niezb&#281;dnego dla modeli &lt;span class="caps"&gt;ORM&lt;/span&gt;. Nie mamy te&#380; czasu (ani ochoty) aby siedzie&#263; i stworzy&#263; definicje do wszystkich tabel wraz z wyposa&#380;eniem ich w nasze w&#322;asne, dodatkowe metody uwzgl&#281;dniaj&#261;ce ka&#380;d&#261;, mo&#380;liw&#261; potrzeb&#281; w przysz&#322;o&#347;ci.  Zamiast tego, wolimy tworzy&#263; i  rozbudowywa&#263; obiektowy opis naszej bazy dla wszystkich aplikacji w miar&#281; ich rozwoju i wzrostu z&#322;o&#380;ono&#347;ci.  Chcemy oby nasz model biznesowy, opisywany przez ActiveRecord, r&#243;s&#322; stopniowo wraz ze wzrostem naszych aplikacji RoR.&lt;/p&gt;


	&lt;p&gt;Do takiego zadania, najlepiej aby wszystkie aplikacje RoR korzysta&#322;y ze wsp&#243;lnego repozytorium modeli. W wypadku system&#243;w &lt;span class="caps"&gt;POSIX&lt;/span&gt; (Linux, czy MacOS-X) najpro&#347;ciej to rozwi&#261;za&#263; za pomoc&#261; link&#243;w symbolicznych. Jednak&#380;e, je&#347;li chcemy aby nasz kod by&#322; bardziej przeno&#347;ny i dzia&#322;a&#322; tak&#380;e pod Windowsami musimy inaczej podej&#347;&#263; do tego problemu: wyniesiemy definicje naszych modeli do zewn&#281;trznych modu&#322;&#243;w Rubiego aby domieszkowa&#322;y one klasy poszczeg&#243;lnych modeli Rails.&lt;/p&gt;


	&lt;p&gt;Wpierw musimy dla ka&#380;dej aplikacji RoR wskaza&#263; gdzie le&#380;y repozytorium z wpo&#322;dzielonymi  modu&#322;ami. Najlepiej wstawi&#263; do pliku conf/environment.rb zmienn&#261; globaln&#261; Rubiego o nazwie, np. $SHARED.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="global"&gt;$SHARED&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;File&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;dirname&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;__FILE__&lt;/span&gt;&lt;span class="punct"&gt;)+'&lt;/span&gt;&lt;span class="string"&gt;/../../shared/&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Konstrukcja File.dirname&amp;#8230; jest zalecana, gdy&#380; daje pewny i jednoznaczny dost&#281;p do pliku bez wzgl&#281;dy na to gdzie przekopiujemy ca&#322;y nasz projekt. (Identycznie nale&#380;y robi&#263; pod &lt;span class="caps"&gt;PHP&lt;/span&gt; aby unikn&#261;&#263; problem&#243;w z ustawieniami zmiennej include_dirs. Wi&#281;kszo&#347;&#263; pehapowego lamerstwa u&#380;ywa zapisu require(&amp;#8220;plik.php&amp;#8221;) i potem si&#281; dziwi &#380;e co&#347; im nie dzia&#322;a)&lt;/p&gt;


	&lt;p&gt;Za&#322;&#243;&#380;my &#380;e wcze&#347;niej mieli&#347;my model  zdefiniowany nast&#281;puj&#261;co:&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;Book&lt;/span&gt;
  &lt;span class="ident"&gt;set_table_name&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;ksiazki&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;
  &lt;span class="ident"&gt;belongs_to&lt;/span&gt; &lt;span class="symbol"&gt;:author&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;self.commented&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="constant"&gt;self&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;: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="string"&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="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;Mamy tu wi&#281;c nie tylko nazw&#281; tabeli niezgodn&#261; z konwencj&#261; Rails&#243;w, ale tak&#380;e dodatkow&#261; metod&#281; klasow&#261;. Wpierw zr&#243;bmy z tego modu&#322;:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;module &lt;/span&gt;&lt;span class="module"&gt;BookModule&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;self.extended&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;c&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;set_table_name&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;ksiazki&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;belongs_to&lt;/span&gt; &lt;span class="symbol"&gt;:author&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;commented&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="constant"&gt;self&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;: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="string"&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="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;Kod korzystaj&#261;cy z tego modu&#322;u przyjmie posta&#263;:&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;RAILS_ENV&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;development&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
  &lt;span class="ident"&gt;load&lt;/span&gt; &lt;span class="global"&gt;$SHARED&lt;/span&gt; &lt;span class="punct"&gt;+&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;models/book.rb&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;
&lt;span class="keyword"&gt;else&lt;/span&gt;
  &lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="global"&gt;$SHARED&lt;/span&gt; &lt;span class="punct"&gt;+&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;models/book.rb&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;class &lt;/span&gt;&lt;span class="class"&gt;Book&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;include&lt;/span&gt; &lt;span class="constant"&gt;BookModule&lt;/span&gt;
  &lt;span class="ident"&gt;extend&lt;/span&gt; &lt;span class="constant"&gt;BookModule&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;G&#243;rny fragment jest potrzebny je&#347;li chcemy aby Webrick/Mongrel w trybie development si&#281; prze&#322;adowywa&#322; podczas zmiany kodu w Ruby. &amp;#8220;include&amp;#8221; w&#322;&#261;cza metody instancji.  Za&#347; &amp;#8220;extend&amp;#8221; w&#322;&#261;cza wszystkie emetody modu&#322;u _BookModule _do klasy jako jej metody &lt;strong&gt;klasowe&lt;/strong&gt;. Zwr&#243;&#263; uwag&#281;, &#380;e w module nie definiowali&#347;my ich jako z prefiksem self.  Co prawda, efektem ubocznym tego przyk&#322;adu jest to, &#380;e metoda commented() b&#281;dzie mo&#380;liwa do uruchomienia jako metoda zar&#243;wno instancji jak i klasy, ale to raczej nie ma &#380;adnego znaczenia.&lt;/p&gt;</description>
      <pubDate>Wed, 04 Oct 2006 17:01:00 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:c5f8cc00-6a5c-414b-9df7-beeb67e3259a</guid>
      <author>Jaros&#322;aw Zabie&#322;&#322;o</author>
      <link>http://blog.zabiello.com/articles/2006/10/04/flexiblerails</link>
      <category>Ruby on Rails</category>
      <category>rails</category>
      <category>activerecord</category>
      <category>orm</category>
    </item>
    <item>
      <title>"Elastyczno&#347;&#263; Rails&#243;w" by lopex</title>
      <description>&lt;p&gt;enterprise to mo&#380;e Zope a i tak nuxeo z niego zrezygnowa&#322;, nie s&#261;dze aby django/rails by&#322;y cho&#263; troche enterprisey.
W tej chwili eksperymentuj&#281; z jruby/ejb &amp;#8211; to ju&#380; bardziej&amp;#8230;&lt;/p&gt;</description>
      <pubDate>Sat, 07 Oct 2006 18:35:39 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:fc2465e2-23d2-4fb4-8763-d77f351af3f6</guid>
      <link>http://blog.zabiello.com/articles/2006/10/04/flexiblerails#comment-246</link>
    </item>
    <item>
      <title>"Elastyczno&#347;&#263; Rails&#243;w" by maniel</title>
      <description>&lt;p&gt;ooo, w&#322;a&#347;nie, s/schematy/migrations/ zapomnia&#322;em jak to si&#281; zwie:P A co do odpytywania bazy dopiero przy pobieranbiu danych, to jest bardzo dobry pomys&#322;. Nie wiem czemu w AR tego nie ma, pewnie dlatego ze nie zostal pomy&#347;lany do rozwi&#261;za&#324; typu enterprise podczas gdy django bylo od pocz&#261;tku pisane z tym na my&#347;li [afaik]. Przydatna to rzecz gdy kto&#347; wsadza du&#380;o danych do bazy.&lt;/p&gt;</description>
      <pubDate>Sat, 07 Oct 2006 18:07:31 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:a21d2196-fa2d-4ea0-a00d-56da256ca0ce</guid>
      <link>http://blog.zabiello.com/articles/2006/10/04/flexiblerails#comment-245</link>
    </item>
    <item>
      <title>"Elastyczno&#347;&#263; Rails&#243;w" by lopex</title>
      <description>&lt;p&gt;No i w&#322;a&#347;nie po to s&#261; pluginy. Nie znalaz&#322;em w &#380;adnym innym framewarku nic lepszego ni&#380; ease-where (no.. w lispie da sie lepiej).&lt;/p&gt;


	&lt;p&gt;jest te&#380; plugin:
&lt;a href="http://agilewebdevelopment.com/plugins/paginating_find" rel="nofollow"&gt;http://agilewebdevelopment.com/plugins/paginating_find&lt;/a&gt;
ale nie jest on ca&#322;kiem lazy.&lt;/p&gt;


	&lt;p&gt;Mo&#380;na si&#281; pobawi&#263; enumeratorem z Rubiego &amp;#8211; taki odpowiednik Pythonowych generator&#243;w, dla uzyskania pe&#322;nego lazy loading (ale niestety w bebechach AR)&lt;/p&gt;</description>
      <pubDate>Sat, 07 Oct 2006 13:48:33 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:b30bb584-b333-4220-bab7-6fc08cd9129f</guid>
      <link>http://blog.zabiello.com/articles/2006/10/04/flexiblerails#comment-244</link>
    </item>
    <item>
      <title>"Elastyczno&#347;&#263; Rails&#243;w" by Jaros&#322;aw Zabie&#322;&#322;o</title>
      <description>&lt;p&gt;Nie wiem co ci si&#281; nie podoba w LOOKUP_SEPARATOR i QUERY_TERMS? Mo&#380;e to rzecz gustu, ale mnie si&#281; to znacznie bardziej podoba od klepania SQL&amp;#8217;a dla :conditions w Active Record.&lt;/p&gt;


	&lt;p&gt;Nie rozumiem o co ci chodzi z tym method_missing?&lt;/p&gt;


	&lt;p&gt;Nie wiem jak to jest rozwi&#261;zane w w ActiveRecord, ale Django stosuje lazy queries, odpytuje si&#281; bazy dopiero w momencie pobierania danych. To jest znacznie lepsze rozwi&#261;zanie, bo pozwala na bardziej wydajn&#261; implementacj&#281; zapyta&#324; (nic dziwnego, &#380;e Django jest znacznie szybsze od Rails&#243;w).&lt;/p&gt;


ActiveRecord od razu zapytuje si&#281; bazy i zwraca list&#281; :(
&lt;pre&gt;&lt;code&gt;p MyModel.find(:all).class 
&amp;gt;&amp;gt;&amp;gt; Array&lt;/code&gt;&lt;/pre&gt;

Django za&#347; zwraca &lt;strong&gt;obiekt&lt;/strong&gt; QuerySet:
&lt;pre&gt;&lt;code&gt;print type(MyModel.objects.all())
&amp;gt;&amp;gt;&amp;gt; &amp;lt;class 'django.db.models.query.QuerySet'&amp;gt;&lt;/code&gt;&lt;/pre&gt;</description>
      <pubDate>Sat, 07 Oct 2006 02:12:46 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:f886c7a1-3858-42ae-9d3e-97d6a155a54c</guid>
      <link>http://blog.zabiello.com/articles/2006/10/04/flexiblerails#comment-243</link>
    </item>
    <item>
      <title>"Elastyczno&#347;&#263; Rails&#243;w" by Jaros&#322;aw Zabie&#322;&#322;o</title>
      <description>&lt;p&gt;W Railsach te&#380; mo&#380;esz tworzy&#263; struktur&#281; bazy w czystym Ruby i Rails wygeneruje odpowiedni kod SQL tworz&#261;c tabelki. Ma&#322;o tego, tak&#261; operacj&#281; mo&#380;esz wersjonowa&#263; i niedestrukcyjnie (dla danych) cofa&#263; si&#281; do wcze&#347;niejszych wersji bazy. To si&#281; nazywa &lt;a href="http://wiki.rubyonrails.com/rails/pages/UnderstandingMigrations" rel="nofollow"&gt;Migrations&lt;/a&gt;.&lt;/p&gt;</description>
      <pubDate>Sat, 07 Oct 2006 00:33:09 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:88e4430e-3190-406d-8b0c-e30137831b35</guid>
      <link>http://blog.zabiello.com/articles/2006/10/04/flexiblerails#comment-242</link>
    </item>
    <item>
      <title>"Elastyczno&#347;&#263; Rails&#243;w" by maniel</title>
      <description>&lt;blockquote&gt;
		&lt;p&gt;W przeciwie&#324;stwie do innych ORM&#8217;&#243;w, railsowy ActiveRecord nie wymaga &#380;adnego wcze&#347;niejszego definiowania p&#243;l. Ruby bez problemu sam sobie wyciagnie wszystkie nazwy p&#243;l w spos&#243;b dynamiczny wtedy, kiedy b&#281;dzie mu to potrzebne.&lt;/p&gt;
	&lt;/blockquote&gt;


	&lt;p&gt;Dla mnie w ORM wa&#380;na jest przeno&#347;no&#347;&#263; i automatyka tworzenia tabel, w ActiveRecord, o ile dobrze pami&#281;tam, trzeba tworzy&#263; schemat, oddzielajac go od modelu. Mi to z deczka nie pasuje dlatego bardziej podoba mi si&#281; nitrowe OG gdzie w modelu definiuj&#281; pola, po czym  automatycznie utworzona mi zostanie tabela odwzorowuj&#261;ca [odwzorowywuj&#261;ca?] ten&#380;e model. Tak samo jest z reszt&#261; w django. Ale kto co lubi, ja jestem za takim w&#322;a&#347;nie rozwiazaniem, zamiast r&#281;cznego tworzenia tabeli albo te&#380; pisania iddzielnie jakiego&#347; skryptu kt&#243;ry tworzy mi tabele:)&lt;/p&gt;</description>
      <pubDate>Fri, 06 Oct 2006 21:11:03 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:376dbc69-00dd-4498-b81b-9926e2d7f0fe</guid>
      <link>http://blog.zabiello.com/articles/2006/10/04/flexiblerails#comment-241</link>
    </item>
    <item>
      <title>"Elastyczno&#347;&#263; Rails&#243;w" by lopex</title>
      <description>&lt;p&gt;z tym ORM django bym nie przesadza&#322; ;)
zobacz sobie na paskudn&#261; obs&#322;ug&#281; LOOKUP_SEPARATOR i QUERY_TERMS &amp;#8211; to jest du&#380;o gorsze od method_missing ;)&lt;/p&gt;</description>
      <pubDate>Fri, 06 Oct 2006 16:23:32 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:e949896e-6ebb-4a3f-b356-fc1a7da63206</guid>
      <link>http://blog.zabiello.com/articles/2006/10/04/flexiblerails#comment-240</link>
    </item>
    <item>
      <title>"Elastyczno&#347;&#263; Rails&#243;w" by Jaros&#322;aw Zabie&#322;&#322;o</title>
      <description>&lt;p&gt;To wygl&#261;da ciekawie, jednak mam wra&#380;enie, &#380;e (1) to bardziej bajer ni&#380; jakie&#347; znacz&#261;ce ulepszenie jako&#347;ci ORM&amp;#8217;a (vide znacznie lepszy ORM jaki ma Django), (2) ta ca&#322;a idea plugin&#243;w zmieniaj&#261;cych Railsy podoba mi si&#281; tak sobie, bo kod staje si&#281; troch&#281; nieprzewidywalny. Tutaj bym broni&#322; podej&#347;cia pythonowego. Mniej magii i zgadywania co do czego s&#322;u&#380;y przy zachowaniu r&#243;wnej prostoty kodu. A je&#347;li taki &amp;#8220;feature&amp;#8221; jest a&#380; tak dobry, to niech zostanie do&#322;&#261;czony do g&#322;&#243;wnego kodu Rails&#243;w.&lt;/p&gt;</description>
      <pubDate>Fri, 06 Oct 2006 14:27:01 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:afa5039b-9c43-485f-9523-a42ef9bc51eb</guid>
      <link>http://blog.zabiello.com/articles/2006/10/04/flexiblerails#comment-239</link>
    </item>
    <item>
      <title>"Elastyczno&#347;&#263; Rails&#243;w" by lopex</title>
      <description>&lt;p&gt;i poprawka:&lt;/p&gt;


	&lt;p&gt;self.find_where(:all) do |book| user_id == book.user_id
end&lt;/p&gt;</description>
      <pubDate>Wed, 04 Oct 2006 23:09:59 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:8e06f6e1-f140-4210-abfe-fee4fbc37895</guid>
      <link>http://blog.zabiello.com/articles/2006/10/04/flexiblerails#comment-236</link>
    </item>
    <item>
      <title>"Elastyczno&#347;&#263; Rails&#243;w" by lopex</title>
      <description>&lt;p&gt;znowu mi nowe linie zjad&#322;o :(&lt;/p&gt;</description>
      <pubDate>Wed, 04 Oct 2006 23:06:52 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:cdf65c87-b7a3-416c-a810-5d9c071076bc</guid>
      <link>http://blog.zabiello.com/articles/2006/10/04/flexiblerails#comment-235</link>
    </item>
    <item>
      <title>"Elastyczno&#347;&#263; Rails&#243;w" by lopex</title>
      <description>&lt;p&gt;bardzo polecam plugin easy-where dzi&#281;ki kt&#243;remu:&lt;/p&gt;


	&lt;p&gt;self.find(:all, :conditions=&amp;gt;[&amp;#8216;user_id=?&amp;#8217;,user_id])&lt;/p&gt;


	&lt;p&gt;przyjmie posta&#263;:&lt;/p&gt;


	&lt;p&gt;self.find_where(:all) |book|
    user_id  book.user_id
end&lt;/p&gt;


	&lt;p&gt;&#322;adne nie ? Ale mo&#380;na robi&#263; du&#380;o wi&#281;ksze cudawianki (bardzo czytelne):&lt;/p&gt;


	&lt;p&gt;Foo.find(:all) do
    id = [1, 3, 8]
    foo == &amp;#8216;other bar&amp;#8217;
    fiz =~ &amp;#8216;faz&amp;#8216;
    bar &amp;gt; 4
end&lt;/p&gt;


	&lt;p&gt;warunki mo&#380;na r&#243;wnie&#380; tworzy&#263; tak:&lt;/p&gt;


	&lt;p&gt;:condtions =&amp;gt; c{|foo| foo.bar &amp;gt; 4}.to_sql&lt;/p&gt;


	&lt;p&gt;mo&#380;na je te&#380; dodawa&#263; przez + i tworzy&#263; alternatywy przez |.&lt;/p&gt;


	&lt;p&gt;&lt;a href="http://brainspl.at/articles/2006/01/30/i-have-been-busy" rel="nofollow"&gt;http://brainspl.at/articles/2006/01/30/i-have-been-busy&lt;/a&gt;
&lt;a href="http://brainspl.at/articles/2006/06/30/new-release-of-ez_where-plugin" rel="nofollow"&gt;http://brainspl.at/articles/2006/06/30/new-release-of-ez_where-plugin&lt;/a&gt;&lt;/p&gt;


	&lt;p&gt;a ostatni feature to ju&#380; jest bajer!
&lt;a href="http://brainspl.at/articles/2006/10/03/nested-joins-and-ez-where-update" rel="nofollow"&gt;http://brainspl.at/articles/2006/10/03/nested-joins-and-ez-where-update&lt;/a&gt;&lt;/p&gt;</description>
      <pubDate>Wed, 04 Oct 2006 23:05:56 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:5602c619-2a15-4d90-a4ae-4645681757a6</guid>
      <link>http://blog.zabiello.com/articles/2006/10/04/flexiblerails#comment-234</link>
    </item>
  </channel>
</rss>
