Hlavní navigace

Ruby on Rails: Jednoduchá aplikace

18. 11. 2005
Doba čtení: 12 minut

Sdílet

Slíbil jsem přátelům, že jim do Vánoc udělám stránky. Jak už to chodí, sliby jsou sliby a Vánoce jsou tu. Ano, je to hrozné, ale stává se to každoročně. Stránky jsem se rozhodl vytvořit v Rails a popsat celý proces právě na Root.cz.

Má to řadu výhod, jednak bych se do nich jinak asi nedonutil, jednak předpokládám, že přínos bude větší, než kdybych se pouštěl do umělého internetového obchodu, který by stejně nikomu nic neřekl. Zejména z případné diskuse určitě vyplynou alternativní řešení.

O jaké stránky půjde? Umístěny budou na doméně rolldance.cz, budou pojednávat o jízdě na klasických (trackových) kolečkových bruslích a lidech kolem toho. Náplní by měly být profily uživatelů, kniha hostů, blogy, články, galerie a samozřejmě administrační rozhraní. Mimochodem vlevo nahoře.

RollDance

Nejprve ale Rails nainstalujeme

1. Je třeba mít funkční Ruby. Bývá součástí běžných *nixových distribucí a mělo by být alespoň ve verzi 1.8.2. Zkuste verzi Ruby otestovat:

mig> ruby --version
ruby 1.8.3 (2005-09-21) [i686-linux] 

2. Rails a případné další komponenty nainstalujeme online pomocí RubyGems. Jde o speciální balíčkovací systém určený pro snadné rozšiřování instalace Ruby. I přesto, že používáte balíčkovací systém své distribuce, můžete využít gemů. Nástroj RubyGems však nemusí být součástí vaší instalace Ruby, pročež jej budete muset doinstalovat (užitím balíčkovacího systému distribuce či stažením tarballu ze stránek projektu, jeho rozbalením a spuštěním ruby setup.rb). Předpokládejme, že RubyGems máte:

mig> gem --version
0.8.11 

3. Pomocí gems nainstalujeme Rails a jejich závislosti.

mig> gem install rails --include-dependencies 

Poznámka: Aktualizovat stávající verzi Rails je též snadné:

mig> gem update rails 

Vytvoření projektu

Samá voda

Vstupte do adresáře, v němž chcete Rails zkoušet. Pomocí příkazu „ rails rolldance“ v něm vytvořte podadresář rolldance obsahující celou funkční strukturu webové aplikace.

mig> cd /Depot/tempik/

mig> rails rolldance
mig> cd rolldance
mig> ls
app  CHANGELOG  components  config  db  doc  lib  log  public  Rakefile  README  script  test  vendor 

Co dál? Než si popíšeme některé adresáře, Rails vyzkoušíme. Nemusíte kvůli tomu instalovat Apache, pro zkušební účely využijeme http server WEBrick, který je napsán v Ruby a je součástí instalace Ruby. Rails spuštění a nakonfigurování WEBricku usnadňují jednoduchým skriptem. Upozornění: Jakékoli skripty z adresáře scripts je třeba spouštět z kořenového adresáře Rails, neboť obsahují relativní cesty. WEBrick ukončíte ctrl-c.

mig> script/server
=> Rails application started on http://0.0.0.0:3000

=> ctrl-c to shutdown server; call with --help for options
[2005-11-16 08:13:54] INFO  WEBrick 1.3.1
[2005-11-16 08:13:54] INFO  ruby 1.8.2 (2004-12-25) [i686-linux]
[2005-11-16 08:13:54] INFO  WEBrick::HTTPServer#start: pid=12314 port=3000 

V prohlížeči zadejte adresu http://localhos­t:3000. Měla by se objevit tato stránka:

Congrats

Přihořívá

Podívejme se do adresáře public.

mig> ls public

dispatch.cgi  dispatch.fcgi  dispatch.rb  favicon.ico  images  index.html  javascripts  stylesheets  404.html  500.html 

Adresář public tvoří document root naší aplikace. To znamená, že přes url nebudou dostupné žádné adresáře o úroveň výš, čímž zůstane jejich obsah chráněn. Stránka s gratulací, kterou doufám vidíte, se nachází v souboru public/index.html. Tento soubor smažte a obnovte stránku v prohlížeči.

mig> rm public/index.html 
Routing err

Co se stalo? WEBrick nenalezl index.html, a proto předal požadavek Rails. Teď se tedy ukázal opravdový výstup z Rails, nikoli statická html stránka.

Hoří

Grafika stránek rolldance zatím není hotova, budeme pracovat nanečisto. Zkusíme začít Hlavní stránkou a stránkou O nás, obě budou víceméně statické a není vyloučeno, že je později úplně změníme. Jedná se jen o prototyp a prototypování je silnou vlastností Rails.

Analogicky k PHP, v následující části vyrobíme index.php a o_nas.php.

Protože jsou Rails postaveny na MVC architektuře (Model – View – Controller), je nezbytné začít alespoň kontrolérem a pohledem. Model zatím vynecháme, ač je jednou z nejsilnějších vlastností Rails, jež je odlišuje od ostatních frameworků. Náš kontrolér, pracovně nazvaný Rolldance, se bude starat o Hlavní stránku a stránku O nás.

mig> script/generate controller Rolldance

      exists  app/controllers/
      exists  app/helpers/
      create  app/views/rolldance

      exists  test/functional/
      create  app/controllers/rolldance_controller.rb
      create  test/functional/rolldance_controller_test.rb

      create  app/helpers/rolldance_helper.rb 

Je zřejmé, že se kontroléry i pohledy nacházejí v adresáři app. Předesílám, že tamtéž v budoucnu budou všechny naše kódy, snad kromě případných externích knihoven.

mig> ls app/

apis  controllers  helpers  models  views
mig> ls app/controllers/
application.rb  rolldance_controller.rb
mig> ls app/views/

layouts  rolldance 

Začneme úpravou kontroléru. Původně skoro prázdný soubor app/controller­s/rolldance_con­troller.rb doplníme o metody „index“ a „o_nas“ (analogie index.php a o_nas.php).

app/controller­s/rolldance_con­troller.rb

class RolldanceController < ApplicationController

   def index
   end

   def o_nas
   end

end 

Kontrolér máme. Zbývá vytvořit odpovídající pohledy, jinými slovy soubory app/views/rolldan­ce/index.rhtml a app/views/rolldan­ce/o_nas.rhtml.

app/views/rolldan­ce/index.rhtml

<h1>Hlavní stránka</h1>

   dnešní datum: <%= Time.now %> (přibližně
        <% if Time.now.day <= 15 %>
            první

        <% else %>
            druhá
        <% end %>

   polovina měsíce )<br />
   <%= link_to 'O nás', :action=>'o_nas' %> 

app/views/rolldan­ce/o_nas.rhtml

<h1>O nás</h1>
   Jsme parta nadšenců, kteří bla bla bla...<br />
   <%= link_to 'Zpět na hlavní stránku', :action=>'index' %> 

Výsledek vyzkoušejte na adrese http://localhos­t:3000/rolldan­ce či na adrese http://localhos­t:3000/rolldan­ce/index. Na hlavní stránce by se mělo zobrazit datum a v závorce informace o tom, kterou půlku měsíce máme.

Jak Rails poznají, co je kontrolér a co je akce? V našem případě „rolldance“ odpovídá názvu kontroléru, „index“ akci. Pokud není akce uvedena, je defaultně použita akce index. Tato základní pravidla lze samozřejmě předefinovat.

Oddělení logiky od obsahu

Nezdá se vám šablona hlavní stránky v pořádku? Mně také ne, a ani z pohledu MVC není dobrá, neboť obsahuje programovou logiku. Vrátíme se k ní však později.

Nejdříve se podíváme na ERb (Embedded Ruby) značky v šabloně. Stejně jako v PHP 5 existují i v ERb značky dvojího typu, <% %> a <%= %>. První z nich vykonává Ruby kód, ale nic nezobrazuje, druhá vloží na své místo hodnotu posledního uvnitř provedeného výrazu, používáme ji tedy jako echo.

Značek se v šablonách hojně využívá, především ve spojení s pomocnými metodami (helpers). Jednu z nich, link_to, jsem v příkladu použil. Namísto toho, abych psal přímo <a href='/rolldan­ce/o_nas''>O n­ás</a>, nahradil jsem anchor tag voláním metody link_to. Proč? Později nebudu muset měnit url ve všech šablonách, jestliže přejmenuji akci či kontrolér. Navíc táž akce a tentýž kontrolér může být dostupný ze dvou různých url.

Pomocné metody (helpers) jsou zdokumentovány v rails API, knize ukolébavek pro děti i dospělé, sekci ActionView::Hel­pers.

Ale vraťme se k šabloně hlavní stránky a otázce, co je v ní špatně. Jak jsem psal, obsahuje programovou logiku – určení poloviny měsíce. Zkusíme kód přemístit tam, kam patří, to jest ze šablony hlavní stránky do kontroléru a jeho metody index.

app/controller­s/rolldance_con­troller.rb

class RolldanceController < ApplicationController

   def index
      if Time.now.day <= 15
         @pulka = 'první'
      else

         @pulka = 'druhá'
      end
      @datum = Time.now
   end


   def o_nas
   end

end 

app/views/rolldan­ce/index.rhtml

 <h1>Hlavní stránka</h1>
   dnešní datum: <%= @datum %> (přibližně <%= @pulka %>)<br />
   <%= link_to 'O nás', :action=>'o_nas' %> 

Hned to vypadá lépe, že? Princip kontroléru-šablony není složitý, proměnné objektu, tedy data, která „uvaří“ kontrolér, jsou dostupné v šabloně. V kontroléru tyto proměnné nastavíme, v šabloně je vytiskneme.

Ptáte se, co dělají ty zavináče? V Ruby odlišují proměnné objektu od lokálních proměnných metod; v PHP by jejich zápis odpovídal $this->pulka a $this->datum.

Layout

Možná jste si všimli, že jsem šablony záměrně neobalil počátkem ani koncem html. Učinil jsem tak proto, že společné části obou stránek nemá smysl psát do každé šablony zvlášť, nýbrž je sdílet. Sdíleným částem se říká layout a nejde o nic jiného než speciální šablonu, v našem případě soubor app/views/lay­outs/rolldance­.rhtml. Vytvořte jej a zkopírujte do něj

app/views/lay­outs/rolldance­.rhtml

<html>
<head><title><%= @title %></title></head>
<body>

   <%= @content_for_layout %>
</body>
</html> 

@content_for_layout je proměnná, která obsahuje buď zpracovaný vnitřek Hlavní stránky, nebo stránky O nás. Navíc, díky tomu, že jsou veškerá data „uvařena“ již v kontroléru, může být takto získanou proměnnou i titulek stránky. Nastavíme proměnnou @title v kontroléru tak, aby titulky stránek odpovídaly akcím.

app/controller­s/rolldance_con­troller.rb

class RolldanceController < ApplicationController

   def index
      @title = 'Rolldance: Hlavní stránka'
      if Time.now.day <= 15

         @pulka = 'první'
      else
         @pulka = 'druhá'
      end

      @datum = Time.now
   end

   def o_nas
      @title = 'Rolldance: O nás'
   end

end 

Shrňme si, co jsme zatím vytvořili. Máme kontrolér, šablony a layout. Zatím nepoužíváme žádné výstupy z databáze ani lokalizaci. Stránky jsou víceméně statické.

Debug

Autoři Rails obvykle odsouvají ladění do méně důležitých částí příruček, ale podle mých zkušeností bylo ladění tím prvním, co jsem potřeboval. Bez něj se programování stává dřinou.

Ladění výpisem do šablony I

V kontroléru z principu není možné používat echo či print_r, jak jsme zvyklí z PHP, a zobrazovat data přímo do stránky. Jediné místo, kde tento způsob můžeme použít, je šablona. Helper k účelu sloužící se jmenuje debug.

app/views/rolldan­ce/index.rhtml

<h1>Hlavní stránka</h1>

   <%= debug @pulka %>
   <%= debug @datum %>
   dnešní datum: <%= @datum %> (přibližně <%= @pulka %>)<br />

   <%= link_to 'O nás', :action=>'o_nas' %> 

Ještě jednou připomínám, že proměnné @pulka a @datum byly vytvořeny v kontroléru a nalezneme je i zde v šabloně. Abychom simulovali print_r z PHP a mohli používat jeho obdobu v kontroléru, musíme přidat, nejlépe přímo do layoutu, výpis proměnné @debug, do níž v kontroléru přiřadíme to, co chceme zobrazit.

app/controller­s/rolldance_con­troller.rb

class RolldanceController < ApplicationController

   def index
      @title = 'Rolldance: Hlavní stránka'
      if Time.now.day <= 15

         @pulka = 'první'
      else
         @pulka = 'druhá'
      end

      @debug = @pulka
      @datum = Time.now
   end

   def o_nas
      @title = 'Rolldance: O nás'

   end

end 

app/views/rolldan­ce/index.rhtml

<html>

<head><title><%= @title %></title></head>
<body>
   <%= debug @debug %>
   <%= @content_for_layout %>
</body>
</html> 

Ladění výpisem do šablony II

Helper debug vypisuje celé objekty a činí tak s pomocí YAML. Výše uvedený příklad neumožňuje vypsat více proměnných najednou. Ukážeme si způsob, jak z proměnné @debug udělat pole, a problém tím vyřešit. Nebudeme navíc plnit přímo pole @debug, ale napíšeme speciální metodu dbg, aby to „bylo hezčí“. Vložte ji do souboru app/controller­s/application­.rb, jenž je zděděn ostatními kontroléry, aby byla dostupná ve všech kontrolérech.

app/controller­s/application­.rb:

# The filters added to this controller will be run for all controllers in the application.
# Likewise will all the methods added be available for all controllers.
class ApplicationController < ActionController::Base

   def dbg item
      # inicializace pole, neni-li
      @debug ||= []

      # pridani polozky do pole
      @debug << item
   end

end 

app/controller­s/rolldance_con­troller.rb:

class RolldanceController < ApplicationController

   def index
      @title = 'Rolldance: Hlavní stránka'

      if Time.now.day <= 15
         @pulka = 'první'
      else
         @pulka = 'druhá'

      end
      dbg @pulka
      dbg self.instance_variables
      dbg Time.now.day
      dbg Time.now

      @datum = Time.now
   end

   def o_nas
      @title = 'Rolldance: O nás'
   end

end 

Ladění breakpointerem

Rails nabízejí skvělou možnost ladění – interaktivní vzdálenou konzoli. Nebudeme se připojovat vzdáleně, proto breakpointer (konzoli) spustíme bez parametrů

mig> script/breakpointer

o connection to breakpoint service at druby://localhost:42531 (DRb::DRbConnError)
Tries to connect will be made every 2 seconds... 

Teď už nezbývá než vložit na určité místo kódu metodu „breakpoint“ s volitelnou poznámkou jako parametrem.

app/controller­s/rolldance_con­troller.rb

class RolldanceController < ApplicationController

   def index
      @title = 'Rolldance: Hlavní stránka'
      if Time.now.day <= 15

         @pulka = 'první'
      else
         @pulka = 'druhá'
      end

      breakpoint 'koukni se na @pulka'
      @datum = Time.now
   end

   def o_nas
      @title = 'Rolldance: O nás'

   end

end 

Jakmile se prohlížečem podíváme na stránku, v místě breakpointu se provádění programu zastaví a Rails vytvoří server, k němuž se automaticky připojí breakpointer (konzole).

Na konzoli lze pracovat, jako kdybychom byli přímo uvnitř metody, a to v místě breakpointu. Můžeme vypisovat proměnné, nastavovat je, spouštět ostatní metody a tak dále.

Executing break point "koukni se na @pulka" at ./script/../config/../app/controllers/rolldance_controller.rb:8 in `index'
irb(#<RolldanceController:0x4087b3fc>):001:0> @pulka
=> "druha"

irb(#<RolldanceController:0x407c0584>):003:0> self.instance_variables

=> ["@datum", "@url", "@template", "@__bp_file", "@session", "@performed_redirect", "@assigns", "@request", "@__bp_line", "@pulka", "@action_name", "@action_methods", "@headers", "@response", "@performed_render", "@cookies", "@params"]
irb(#<RolldanceController:0x407c0584>):004:0> @pulka = 'prvni'
=> "prvni" 

Pokud hledáte nějakou proměnnou či metodu, mohou vám posloužit výpisy z těchto metod:

self
self.methods
self.instance_variables 

Breakpointer ukončíte ctrl-d a program bude pokračovat v běhu.

Logování

Poslední způsob, o němž se chci dnes zmínit, je logování. Výstup loggeru najdete v souboru log/developmen­t.log. (Jak se liší development, production a test, bude objasněno v příštím dílu, nyní si řekněme jen to, že Rails mohou fungovat v několika stavech, které například ovlivňují právě logování. Development patří mezi „ukecané“ stavy, takže v logu naleznete i provedené SQL dotazy s jejich dobou trvání. Přepnout stav je možné změnou proměnné prostředí RAILS_ENV.)

Logger se používá jednoduše; kromě metod info a fatal existují ještě metody warn a error.

CS24_early

app/controller­s/rolldance_con­troller.rb

class RolldanceController < ApplicationController

   def index
      logger.info 'INFO: Jsme v metode index'
      @title = 'Rolldance: Hlavní stránka'

      if Time.now.day <= 15
         @pulka = 'první'
      else
         @pulka = 'druhá'

      end
      logger.fatal 'FATAL ERROR: chyba Ruby' if @pulka != 'prvni' && @pulka != 'druha'
      @datum = Time.now
   end

   def o_nas
      @title = 'Rolldance: O nás'
   end

end 

Závěr

V příštím dílu si povíme o práci s hezkými url (pretty-url) a konečně použijeme model, který jsme zatím ignorovali.

Seriál: Ruby on Rails

Byl pro vás článek přínosný?