Zpříjemněte si vývoj webových stránek s frameworkem Ruby on Rails (díl 2.)

Martin Pešout   24. 2. 2011


Když jsem před necelým měsícem začal psát tento článek, tak jsem si říkal, že bych rád všem svým čtenářům přiblížil nástroj, který dennodenně používám ve svém zaměstnání. Jednalo se o webový framework Ruby on Rails. Původně jsem nečekal, že budu nucený kvůli rozsahu celý článek rozdělit do dvou dílů. První část se soustředila na samotný základ a to na programovací jazyk Ruby. Tento článek je dalším pokračováním a je věnován hlavním vlastnostem frameworku Ruby on Rails, které případné zájemce nejvíce zajímají.

Architektura MVC

Ruby on Rails jsou postaveny na návrhovém vzoru Model-View-Controller. Jedná se o základ kvalitního objektového návrhu. V principu MVC rozděluje náš systém do tří logicky nezávislých částí. Na datový model aplikace, uživatelské rozhraní a řídící logiku.

Model-View-Controller

  • Model (Model) - Model zajišťuje zpracování dat. Ve skutečnosti pak představuje jakési rozhraní mezi databází a řadičem.
  • Pohled (View) - Pohled zodpovídá za výsledné zobrazení dat předaných modelem. Podstatné a důležité z hlediska struktury aplikace je to, že samo grafické rozhraní neobsahuje ani vlastní data (to je úkolem modelu), ani logiku práce s nimi (o to se starají řadiče). Jednou z nejběžnějších a nejčastěji opakovaných chyb při objektovém návrhu jsou právě pohledy obsahující data či řídící rutiny.
  • Řadič (Controller) - Řadič přebírá vstupy od uživatele vyvolané vstupními objekty v rámci pohledu (například nabídkami, tlačítky a podobně). Zpracuje je podle potřeby a pak řídí celé zobrazení dat na výstup. Zajišťuje tak logiku chování celého systému. Přitom samozřejmě podle potřeby spolupracuje s modelem. Předává mu požadavky na změny, a kdykoli je to zapotřebí, vyžádá si od něj údaje pro zobrazení.

Webový framework Ruby on Rails

Oficiální verze Ruby on Rails spatřila světlo světa v červenci 2004. Za jeho vznikem stojí dánský programátor David Heinemeier Hansson. Při samotném vývoji byl použit nástroj projektového řízení Basecamp. Jak už bylo několikrát zmíněno, jedná se o takzvaný webový framework. Cílem frameworku je převzetí typických problémů dané oblasti, čímž se usnadní vývoj tak, aby se návrháři a vývojáři mohli soustředit pouze na zadání své práce. Mezi základní princip Rails patří: "Konvence má přednost před konfigurací", tedy, že programátor konfiguruje pouze ty části aplikace, které se liší od běžného nastavení. Vytvoří-li tedy např. model Person, aplikace bude data automaticky hledat v tabulce people. Chce-li, aby aplikace načítala data z jiné tabulky, například users, musí tak učinit výslovně.

Ruby on Rails jsou průlomové v snižování bariér pro vstup do programování. Mocné aplikace, jejichž vývoj v minulosti trval týdny či měsíce, mohou být vytvořeny během několika dní.
--Tim O'Reilly, zakladatel O'Reilly Media

Základní vlastnosti

Při vývoji se zajisté spousta programátorů setkala se situacemi, kdy jsou používány opakujících se částí kódu. Formátování data, správný výpis měny, zobrazení varovných nebo informativních hlášení pro formulářové položky. Lze jich vyjmenovat opravdu hodně. Nikoho tedy nepřekvapí, že Ruby on Rails přichází s řadou rozšíření, jak ulehčit nejčastější případy těchto úkonů. Obsahují tyto dvě základní rozšíření: rozšíření jazyka Ruby (Core Extensions) a pomocné metody (helpers).

Rozšíření jazyka Ruby doplňují základní třídy Array, Date, Hash, NumericStringpohodlné metody (convenience methods), které zjednodušují často se opakující operace. Všechna tato rozšíření velice posilují vyjadřovací schopnost jazyka Ruby. Typickým příkladem může být zjištění, zda je číslo sudé či liché, které lze využít třeba pro střídání barvy pozadí řádků tabulky:

7.even?
=> false

Další pěknou ukázkou je práce s datem, kdy vývojář může chtít zjistit, jaký čas byl před pěti minutami. Stačí pak použít následující volání, které vrátí požadovaný údaj.

5.minute.ago

Pomocné třídy Rails se od rozšíření tříd Ruby liší. Svoje využití mají pouze v pohledech. Slouží opět ke zjednodušení formátování a generování kódu. Typicky tak lze na stránce snadno vytvářet potřebné prvky jazyka HTML. Při potřebě vypsat odkaz lze použít metoda link_to, která vše potřebné obstará za nás.

link_to 'Odstranit záznam', {:controller => 'groups',
:action => 'delete', :id => group}, :confirm => 'Jste si jistý?'

Je-li kladen při vývoji patřičný důraz na to, aby aplikace byla uživatelsky přívětivá, pak jsou vhodnými pomocníky metody, které zavádí do Ruby on Rails určitý návrhový vzor vedoucí k většímu polidštění výpisů dat. Na uživatele působí výsledný systém méně stresujícím dojmem a lidé mají pocit, že aplikace pak "mluví" více jejich jazykem a nekomunikuje s nimi jen prostřednictvím číselných údajů.

time_ago_in_words(5.minute.ago)
=> "5 minutami"

number_to_currency(999)
=> "999,00 Kč"

Těchto zabudovaných metod, které Ruby on Rails nabízí, je opravdu veliké množství. Všechny jsou ale dobře zdokumentované. Nicméně i přes jejich množství se často stává, že je nutné nadefinovat další pomocnou metodu, která se postará například o vykreslení hlavního menu na webové stránce. I s tímto autoři počítali a je tak možné do předem připravené adresářové struktury ukládat nové soubory s vlastními metodami.

Generátory

Velice zajímavými nástroji jsou takzvané generátory kódu. Generátory zaujmou převážně vývojáře seznamující se prvně s tímto frameworkem. Ty nám pomohou při vytváření nových modelů, pohledů a jiných součástí aplikace. Aby vývojáři nemuseli psát všechno ručně, vygenerují pomocí nich základní strukturu automaticky a pak pouze upravují případné detaily. Generátorů je v systému několik. Naprostí začátečníci uvítají zejména scaffold generátory, které umí sestavit k vybrané databázové tabulce formuláře pro zakládání, editaci a mazání dat. Postará se i o vytvoření potřebné tabulky pro výpis dat. Scaffold automaticky vyrobí prvky formuláře podle typů sloupců v databázové tabulce. Takže z typu VARCHAR se stane ve formuláři obyčejné textové pole, z typu BOOLEAN se stane naopak zaškrtávací formulářové pole.

Použití databáze

Pro samotný přístup k databázi je zde použit princip ORM (Object-relational mapping). Ve skutečnosti to pak znamená, že všechny záznamy relační databáze jsou mapovány na objekty. Řádky se převedou na instance objektů a sloupce na jejich atributy. Vytvoření nového záznamu lze demonstrovat na jednoduché ukázce, která uloží do databáze novou osobu.

p = Person.new :first_name => 'Martin', :sure_name => 'Pešout'
p.comment = 'autor odborného článku'
p.save

Díky principu ORM se pracuje v aplikaci pouze s objekty a není nutné psát konkrétní SQL dotazy pro uložení potřebných dat. Programátor není vůbec omezen použitou databází a když se rozhodne v budoucnu použít místo MySQL například databázi PostgreSQL, zamění pouze příslušný adaptér v konfiguračních souborech a nemusí kvůli takovéto změně přepisovat zdrojové kódy. V současné době jsou podporovány následující databáze:

  • MySQL
  • PostgreSQL
  • SQLite
  • SQL Server
  • IBM DB2
  • Informix
  • Oracle
  • Firebird/Interbase
  • LDAP
  • SybaseASA (Sybase Adaptive Server Anywhere aka SQL Anywhere Studio)
  • MonetDB

Při využívání databází narazil zřejmě každý vývojář na problém, jak udržet přehled ve všech úpravách, které nad databázovým schématem provádí. Za tímto účelem byly vytvořeny v Ruby on Rails takzvané migrace. Ty nám umožňují popsat potřebné změny v databázovém schématu a dokonce se vracet v těchto úpravách zpět. Protože se jedná pouze o textové soubory, je již velice snadné tyto záznamy přenést například do Subversion nebo GIT, tj. systému pro správu verzí zdrojových kódů. Každá migrace se skládá ze dvou metod: updown. Vývojář tak dostane možnost v nich definovat akce, které se provedou při procházení historie jednotlivých úprav databázového schématu. Dále je pro existenci migrací významná databázová tabulka schema_info s jedním sloupcem typu INTEGER. Zde se evidují identifikátory již provedených úprav (migrací). Třídy migrací jsou uloženy ve speciálních souborech, které jsou pojmenovány podle vzoru xxx_nazev_migrace.rb, kde xxx je číslo vyjadřující přesný čas vzniku. Následující příklad ukazuje postup při vytvoření tabulky item:

class CreateItems < ActiveRecord::Migration
def self.up
create_table :items do |t|
end
end
def self.down
drop_table :items
end
end

Aplikace v Ruby on Rails může být spuštěna v jednom z několika běhových prostředí, které pak ovlivňují chování jednotlivých částí frameworku. Standardně jsou dostupná tři prostředí:

  • Vývojové - toto prostředí slouží pro vývoj aplikace
  • Testovací - slouží pro spuštění automatických jednotkových a integračních testů
  • Produkční - v tomto prostředí je spouštěna aplikace do ostrého provozu

Připojení k databázi se nastavuje odděleně pro každé prostředí zvlášť. Pro vývojáře to znamená, že tak lze využít oddělené databáze. Je možné tak snadno mít testovací data zvlášť od dat sloužících k ostrému provozu na webu. Aplikace se pak v případě potřeby spustí pouze v požadovaném režimu.

I při samotném návrhu databázového schématu lze využít řadu užitečných konvencí. Pro názvy tabulek se běžně používají anglické názvy objektů, které se reprezentují v množném čísle a malými písmeny. Pokud jsou názvy víceslovné, oddělují se podtržítkem. Příklad lze vidět na následující tabulce.

Název modeluNázev tabulky
Monkeymonkeys
Octopusoctopi
Customercustomers
Monkey Huntermonkey_hunters

Rails očekává název sloupce primárního klíče id. Cizí klíče jsou ve tvaru {jednotné číslo cizí tabulky}_id. Samozřejmě se jedná jen o řadu doporučení, jak navrhovat databázové schéma. Například název sloupce primárního nebo cizího klíče může být i pojmenován jinak. Rails pouze říká, že pokud se využije těchto pravidel, usnadní se tím budoucí práce.

Název tabulkyCizí klíč
monkeysmonkey_id
octopioctopus_id

Programátorská přívětivost jde ještě dál. Při použití speciálních názvů sloupců tabulek je možné docílit také toho, že se budou automaticky vyplňovat některé časové údaje. Sloupec s názvem created_on bude automaticky vyplněn aktuálním časem při vytvoření nového záznamu v tabulce. Ve sloupci updated_on se zas automaticky vyplní čas poslední editace příslušného záznamu. Naplnění hodnotami tak za vývojáře obstará sama aplikace.

Tvorba interaktivních aplikací

V prvních několika letech internetu byly webové aplikace v porovnání se stolními aplikacemi značně pomalé a neohrabané. Lidé měli rádi webové aplikace převážně proto, že byly dostupné kdekoliv, kde bylo dostupné připojení k internetu. Poté firma Microsoft vytvořila tzv. XMLHttpRequest pro svůj internetový prohlížeč Internet Explorer 5. Umožnila tím skriptům na zobrazené stránce komunikovat s webovým serverem v pozadí bez nutnosti načítání nové webové stránky. Vývojář tak může vytvořit více interaktivní aplikace. Brzo po zveřejnění tohoto řešení implementovala i Mozilla a Opera XMLHttpRequest do svých prohlížečů. Zprvu nebyla tato forma komunikace vůbec rozšířená. Do povědomí většího množství lidí ji dostala až společnost Google, které se podařilo vyvinout sérii aplikací komunikujících právě prostřednictvím XMLHttpRequest. Nejznámější je asi Google Maps, poskytující návštěvníkům představu, že jsou schopni přetahovat nekonečně rozsáhlou mapu v okně svého prohlížeče. Využívání XHLHttpRequestu je nyní známo pod jednoduchým názvem AJAX (Asynchronous JavaScript and XML).

Ruby on Rails má jednoduchý, konzistentní model, jak implementovat AJAX. Pokud se v prohlížeči zobrazí úvodní webová stránka, lze pomocí jiné uživatelské akce přejít na novou internetovou stránku (klasické webové aplikace) a nebo spustit některou AJAX operaci:

  1. Došlo ke spouštěcí akci. Ta může nastat například kliknutím na určitý odkaz nebo tlačítko, uživatel mohl změnit data ve formuláři a nebo došlo ke spuštění automatické periodické akce.
  2. Data asociovaná se spouštěcí událostí jsou zaslána asynchronně na server prostřednictvím XMLHttpRequest, kde se o ně postará příslušná akce.
  3. Obsluha dané akce na straně serveru provede programátorem určené operace v závislosti na poskytnutých datech a jako výsledek vrátí příslušný fragment HTML kódu.
  4. Skripty na straně klienta obdrží fragment HTML kódu a použijí ho k aktualizaci specifické části zobrazené HTML stránky.

Aby bylo používání této technologie co nejsnazší, nabízí Ruby on Rails vývojářům několik pomocných metod, které za ně vygenerují ve zdrojovém kódu vše potřebné. Programátor zavolá pouze vhodně vybranou metodu. Pro ukázku zde bude zmíněna AJAX alternativa ke klasické pomocné metodě pro zobrazení odkazu.

link_to('Odstranit záznam', :url => {:controller => 'groups',
:action => 'delete', :id => group}, :remote => true, :confirm => 'Jste si jistý?')

Podpora více jazyků

Zejména u větších projektů je často nutné řešit situace, jak efektivně naprogramovat aplikaci s podporou více jazyků. Ruby on Rails od verze 2.2 poskytuje snadný způsob, jak toho docílit. V rámci vícejazyčné podpory se hovoří o dvou významných procesech. Proces internacionalizace znamená, že se oddělují všechny překládané textové řetězce a další kousky kódu (jako měnu a datum) mimo naši aplikaci. Proces lokalizace pak znamená samotné zajištění překladů a místních formátů (každý stát má jinou měnu nebo jiný způsob zápisu pro datum) pro takovéto kousky textu. Oddělené překlady jsou poté umístěny do speciálních textových souborů. Každý text je v něm označen unikátním klíčem, díky kterému lze poznat v pohledech, jaký popisek se má použít. Jednoduchý soubor s naším přeloženým textem pro anglický jazyk může vypadat třeba následovně:

en:
hello: "Hello world"

V jiném souboru bude uložen stejný překlad, ale pro český jazyk.

cs:
hello: "Ahoj světe"

Pro vypsání našeho textu v pohledu, stačí napsat následující:

t :hello

Aplikace pak pomocí jednoduchých příkazů rozhodne, jaký jazyk se má aktuálně použít. A podle toho se vypíše příslušný anglický nebo český popisek. Toto je samozřejmě jen základní ukázka použití překladů v Ruby on Rails. Je možné využívat i složitějších metod. Překládat lze jednotlivé modely, názvy atributů, rozlišovat jednotné a množné tvary slov apod.

Vylepšení aplikace pomocí pluginů

Další silnou stránkou Ruby on Rails je způsob, jakým lze snadno rozšiřovat poskytované funkce pomocí pluginů. Jedná se o externí knihovny. Jejich použití šetří spoustu času, protože funkčnost, kterou potřebujete, napsal už někdo před vámi a možná dokonce i lépe, než byste to udělali vy. U hojně používaných pluginů je navíc jistější, že bude odstraněna většina chyb. Existuje jich hned celá řada, od těch řešících obecné problémy téměř každé aplikace po pluginy, které jsou určené pro specifické případy. Snadno tak lze naše programy rozšířit o možnost práce s obrázky nebo umožnit jednotlivým uživatelům přihlášení do systému a přiřazení potřebných práv. Pro případné zájemce doporučuji webovou stránku The Ruby Toolbox, která poskytuje velice pěkný přehled nejpoužívanějších pluginů.

Testování

Poslední vlastnost, která bude v tomto článku zmíněna, je testování. Vytváříme-li webovou aplikaci, máme vždy určitou představu, jak by se měla chovat. Čas od času potřebujeme nějakou část upravit nebo přidat nové funkce. Jak se systém postupně rozrůstá, je čím dál víc obtížnější sledovat, jestli se všechny části chovají pořád stejně. Proces vývoje se proto neobejde bez testování. Na provedené úpravy napíše programátor vlastní sadu testů, a pokud všechny kontroly projdou, dostává tak větší záruku, že do systému někdo nezanesl chyby. Samozřejmě vše záleží na tom, s jakou důsledností se testy píší. Testování v Ruby on Rails se dělí do dvou částí:

  • Testy modelů (Unit tests)
  • Testy řadičů (Functional tests)

Proces testování pak probíhá pomocí tvrzení. Jedná se o speciální metody, které zkontrolují vybraný kód. Po spuštění jsou vyhodnoceny buď jako pravda nebo nepravda, podle toho jestli se podařilo potřebný kód prověřit.

Závěrem

O Ruby on Rails by se dalo dlouze rozepisovat. Vlastností, kterýma se tento framework může chlubit, je samozřejmě více. Snažil jsem se trochu přiblížit ty z nich, které mě samotného zaujaly, když jsem se začal seznamovat s tímto programovacím jazykem.

Zdroje a odkazy na podrobnější informace