Innovatieve technologie: Ruby on Rails

door Pieter Hoste

Inleiding

Dit artikel zal zich voornamelijk profileren als een praktische gids over hoe je een Rails applicatie aanmaakt met af en toe een stukje theoretische uitleg tussendoor. Ik doe dit omdat ik ervan overtuigd ben dat je via de praktijk veel meer leert over deze technologie dan via de theorie, dit heb ik zelf ook zo ondervonden.
We zullen hier in dit artikel een forum aanmaken met behulp van Ruby on Rails.

Ruby

Ruby is een objectgeoriënteerde programmeertaal die ontstaan is in het jaar 1993.
Nu vraag je je wellicht af: wat heeft een dertien jaar oude programmeertaal te zien met een innovatieve technologie?. Wel het innovatieve zit hem in het derde woord van de titel, nl: Rails.

Rails

Rails is een web framework gebouwd op Ruby.
De ontwikkeling van Rails is begonnen eind 2004 en bereikte een stabiele 1.0 release op 13 december 2005. Vandaar dat dit aanzien wordt als een zeer innovatieve technologie.

Rails is wat men noemt een rapid web development framework, je moet heel weinig programmeerwerk doen om al een simpele, dynamische website ineen te boksen.

De architectuur van Rails bestaat uit een Model-View-Controller architectuur.
Het Model bestaat uit een representatie van de database tabellen. Rails baseert zich hierbij op de Engelse taal, dus stel dat je een model aanmaakt: Forum, dan zal Rails op zoek gaan naar de tabel forums in de database. Rails is zelfs zo slim om niet enkel een s toe te voegen aan het model, maar baseert zich werkelijk op de Engelse taal, dus als je een model Person aanmaakt, dan zal Rails zoeken naar een tabel people.
De View bestaat uit .rhtml bestanden die html-templates voorstellen, die zich opvullen met data uit de Controllers.
De Controller bevindt zich tussen het Model en de View.

Nu gaan we wat meer ingaan op het technische gedeelte van Rails.

Installatie

Wat moet je allemaal doen om Ruby on Rails te installeren op een Windows-machine?
We beginnen met de installatie van Ruby, momenteel is versie 1.8.4 al gereleased, maar op moment van schrijven is er voor deze versie is nog geen goed installatie pakket samengesteld, dus gaan we versie 1.8.2 installeren (versie 1.8.3 had een aantal zeer vervelende bugs met Rails, dus die gaan we ook niet gebruiken).
We gaan de One-Click Ruby Installer gebruiken die je hier kan vinden:
Download de One-Click Ruby Installer
Het leuke aan deze installer is dat de RubyGems Package Manager en WEBrick (webserver) ook al meegeleverd worden, meer daarover later.
Je doorloopt gewoon alle stappen en na afloop kan je controleren of ruby wel degelijk geïnstalleerd werd, door in de commandoprompt van Windows in te geven: ruby –v

Nu gaan we Rails installeren, hiervoor maken we gebruik van de RubyGems Package Manager.
Nog steeds in je commandoprompt (dewelke je heel regelmatig zal moet gebruiken voor Ruby on Rails) typ je: gem install rails --include-dependencies De installatie van Rails kan gemakkelijk een aantal minuten duren.

Je eerste Rails toepassing

Nu gaan we eens een eerste Rails applicatie in elkaar steken. Wij zullen hier een basis forum applicatie in elkaar steken. Nu zal je denken: een forum, dat is toch heel veel werk?, wel met Ruby on Rails zal je zien dat dit niet het geval is.

Open je commandoprompt en navigeer naar een bepaalde locatie waar je je forum applicatie wil gaan aanmaken (hier is dit: D:\rails\).
Typ dan:rails forum (forum is de naam van de applicatie, die mag je dus gerust veranderen).
Als alles goed gaat, zal er nu een map forum aangemaakt worden met daarin een aantal subfolders die de applicatie voorstellen.
Zo ziet die mapstructuur er momenteel uit: screenshot van de structuur van de forum-map

Nu gaan we deze applicatie eens opstarten, dit doe je door te navigeren naar D:\rails\forum\ en in te geven: ruby script\server Hierdoor wordt de ingebouwde webserver (WEBrick) opgestart en als alles goed gelukt is kan je je applicatie bekijken via deze uri: http://127.0.0.1:3000
Voilà, zo simpel is dat om een Rails applicatie aan te maken, op naar de database configuratie.

Databases

Rails voorziet standaard in ondersteuning voor volgende databasepakketten: MySQL, PostgreSQL, Oracle, SQL Server, DB2 en SQLite.

Ik zal hier gebruik maken van MySQL 5.0, dewelke je hier kan afhalen: Download MySQL 5.0 en phpMyAdmin, welke je hier vind: Download phpMyAdmin

Tip: ik maak eigenlijk gebruik van het XAMPP pakket voor Windows, daarin zit Apache, PHP 4/5, Mysql 5, phpMyAdmin en nog vanalles.
Meer info en installatie instructies vind je hier: XAMPP informatie

Laat ons beginnen met een database forum aan te maken. Een forum bestaat uit forums zelf, topics en posts, dus we gaan deze drie tabellen aanmaken in onze database.
forums tabel: screenshot vanuit phpMyAdmin van de forums tabel topics tabel: screenshot vanuit phpMyAdmin van de topics tabel posts tabel: screenshot vanuit phpMyAdmin van de posts tabel

Nu moeten we nog maken dat Rails onze database herkent, dit doen we door het bestand config\database.yml aan te passen met een teksteditor. Het volgende zet je in dat bestand:

development:
  adapter: mysql
  database: forum
  username: root
  password:

test:
  adapter: mysql
  database: forum
  username: root
  password:

production:
  adapter: mysql
  database: forum
  username: root
  password: 

Nadat je het database.yml bestand aangepast hebt, moet je de webserver wel nog herstarten, dit doe je door de toetsencombinatie Ctrl+C in te geven in het commandovenster waar je server nog aan het draaien is, en daarna geef je opnieuw het startcommando in: ruby script\server Ok, vanaf nu kan Rails dus communiceren met onze database. Op naar het aanmaken van de models, views en controllers.

Models, Views en Controllers

Nu gaan we onze eerste tabel vanuit de database implementeren in Rails. We typen in een nieuwe commandoprompt vanuit de locatie waar onze applicatie zich bevindt (D:\rails\forum\): ruby script\generate scaffold Forum Dit commando zorgt ervoor dat er automatisch een Model, een aantal Views en een Controller worden aangemaakt voor de forums-tabel uit onze database.
Zoals ik hierboven al melde mapt Rails het Model Forum aan het Engelse meervoud: forums en gaat op zoek naar die tabel in de database.
Het scaffold commando heeft al direct een aantal Views aangemaakt, deze bestaan uit html-templates met wat inline Rails code.
Je kan deze al bekijken op volgende uri: http://127.0.0.1:3000/forums

Laat ons nu eens de gegenereerde controller van wat dichterbij bekijken, deze bevindt zich hier: app\controllers\forums_controller.rb. Je opent deze best met een teksteditor.
Wat staat daar nu allemaal in, wel al die def's worden actions genoemd en ze worden aangeroepen via de url die je ingeeft.
In de url hierboven staat geen actie vermeld, maar automatisch wordt die gemapt aan de index-action.
Als we dan eens kijken in de index-action, dan zien we dat die verwijst naar de list-action, dus kun je via drie uri's aan diezelfde list-action komen: http://127.0.0.1:3000/forums, http://127.0.0.1:3000/forums/index en http://127.0.0.1:3000/forums/list

Er staan nog een aantal actions in de controller vermeld, en deze kan je aan het werk zien door bijvoorbeeld New Forum aan te klikken. Je komt dan terecht in de new-action, en deze heeft al direct een textbox neergeplaats om de naam van je forum in te geven. Wel nu, geef maar een naam in, en klik op Create. Dit wordt nu geheel automatisch toegevoegd aan je database, bemerk dat je dus niets van SQL hebt moeten schrijven, Rails regelt dat allemaal voor jou.
Je komt nu terug op de list-action terecht, waar je je nieuwe forum kan bekijken, editeren en verwijderen.
Maak ondertussen nog maar een aantal forums aan, we zullen ze later goed kunnen gebruiken.

Nu gaan we hetzelfde doen voor onze topics en posts, dus we geven volgende commando's in: ruby script\generate scaffold Topic ruby script\generate scaffold Post De resultaten kan je bekijken via: http://127.0.0.1:3000/topics en http://127.0.0.1:3000/posts

Nu moeten we nog maken dat de Topics tot een bepaald forum kunnen behoren en de posts tot een bepaald topic, dat zien we in de volgende sectie.

Relaties

Nu gaan we de topics aan de forums binden en de posts aan de topics, dit bepalen we in de Models. De Models bevinden zich op deze locatie: app\models\.
In forum.rb zetten we dit:

class Forum < ActiveRecord::Base
	has_many :topics
end

In topic.rb komt:

class Topic < ActiveRecord::Base
	belongs_to :forum
	has_many :posts
end

En tenslotte in post.rb komt:

class Post < ActiveRecord::Base
	belongs_to :topic
end

Wat zich hier nu feitelijk achter de schermen afspeelt is het volgende: Rails gaat opzoek in de tabel topics naar het veld forum_id, en zal daaraan het forum koppelen dat hetzelfde id heeft.
Hetzelfde speelt zich af tussen een bepaald topic en zijn posts.

Nu gaan we wel nog de views en de controllers manueel moeten gaan aanpassen zodat je de relaties tussen de Models weldegelijk ziet.

Views en Controllers aanpassen

We zullen beginnen met te maken dat het je in de list-action enkel de forumnaam ziet, met daarop een link naar de topics die tot da forum behoren.
Open alvast het bestand app\views\forums\list.rhtml met een teksteditor.
Je overschrijft het bestand met deze inhoud:

<h1>Forums</h1>
<ul>
<% for forum in @forums %>
  <li>
  	<%= link_to forum.naam, :controller => 'topics',
		:action => 'list', :id => forum %>
  </li>
<% end %>
</ul>

<%= link_to 'New forum', :action => 'new' %>

Hier maak ik een mooi lijstje aan met de namen van elk forum, en op die naam staat een link naar de list-action van de topics, met als parameter het id van het forum.

We gaan nu ook nog maken dat de forums alfabetisch gesorteerd worden weergegeven op hun naam, dit doen we door het bestand app\controllers\forums_controller.rb aan te passen. We gaan de list-action een beetje veranderen:

def list
  @forums = Forum.find :all, :order => 'naam'
end

Als je dit nu al eens uittest en je klikt op de naam van een forum, dan zal er waarschijnlijk nog niet veel verschijnen, want je hebt normaal gezien nog geen topics staan in je database. Voeg er alvast een aantal toe via phpMyAdmin (of iets anders), en maak dat je er verschillende forum_id's aan geeft.
Nadat je die topics toegevoegd hebt, mag je eens je browser refreshen, en je zal zien: alle topics verschijnen en dit zou niet mogen, want er zitten verschillende forum_id's in.
We zullen dus nog de list-action van de topics wat moeten verfijnen om de resultaten wat te filteren, daarvoor moeten de list-action in het bestand app\controllers\topics_controller.rb wat aanpassen:

1. def list
2.  @forum = Forum.find(params[:id])
3.  @topic_pages, @topics = paginate :topics, :per_page => 10,
  	:conditions => ['forum_id = ?', @forum.id],
	:order => 'datum DESC'
4. end

Hier zal ik wat extra uitleg geven:

Lijn2:
er wordt een variabele forum aangemaakt die een object voorstelt van het Model Forum, en die wordt gemaakt aan de hand van de parameter die zich in de url bevindt. Die parameter wordt gemapt aan het id van het forum en zo bekomen we dat ene object.
Lijn3:
Dit zijn 2 variabelen die aangemaakt worden, aangezien er een @-tekentje voorstaat betekent dit dat die variabelen gebruikt kunnen worden in de Views. Er wordt hier gebruik gemaakt van de paginate-functie, maar ik ga hierop niet verder ingaan. Wat belangrijker is, zijn die conditions, daarin zeg ik dat de forum_id's van de topics gelijk moeten zijn aan het id van dat Forum-object van lijn 2.
Ik maak ook gebruik van de order-constructie, waarin ik zeg dat de topics gesorteerd moeten worden op datum, met de nieuwste datum eerst.

Nu nog de view van de list-action van de topics een beetje bijschaven (app\views\topics\list.rhtml):

<h1>Topics uit het Forum <q><%= @forum.naam %></q></h1>
<table>
  <tr>
    <th>Titel</th>
    <th>Datum</th>
  </tr>
<% for topic in @topics %>
  <tr>
    <td><%= link_to topic.titel, :controller => 'posts',
		:action => 'list', :id => topic %></td>
    <td><%= topic.datum.to_formatted_s(:long) %></td>
  </tr>
<% end %>
</table>
<%= link_to 'Previous page', { :page => @topic_pages.current.previous }
	if @topic_pages.current.previous %>
<%= link_to 'Next page', { :page => @topic_pages.current.next }
	if @topic_pages.current.next %>
<%= link_to 'New topic', :action => 'new', :id => @forum %>

Ik heb nu gemaakt dat de titel van het Forum zich bovenaan de pagina genesteld heeft, en dat er een link aangemaakt werd naar de posts met de correcte parameters. Ik ga nu niet meer uitleggen hoe je die posts moet filteren, want dat is hetzelfde principe als de topics filteren.

Ik ga nu gewoon nog maken dat als je een nieuw topic maakt, dat dit zich dan automatisch in het juiste forum positioneert en dat de datum van vandaag ingesteld wordt als postdatum.
Zoals je hierboven kan zien, heb ik in de link naar een New topic het id van het huidige forum waarin je je bevindt meegegeven als parameter.
We zullen dit id in een hidden textfield steken in de file app\views\topics\new.rhtml.

Als we deze file nu eens bekijken dan zien we het volgende staan: <%= render :partial => 'form' %> Deze lijn verwijst naar het bestand _form.rhtml in diezelfde map. Dus we gaan ons hidden textfield in dat bestand moeten steken. Ook zullen we het datum veld uit dat bestand weglaten en dan automatisch via de controller invullen. Dus de inhoud van _form.rhtml wordt dan:

<%= error_messages_for 'topic' %>

<!--[form:topic]-->
<p><label for="topic_titel">Titel</label><br/>
<%= text_field 'topic', 'titel'  %></p>

<%= hidden_field 'topic', 'forum_id', :value => @forum.id %>
<!--[eoform:topic]-->

We wijzigen ook nog de eerste lijn van new.rhtml naar: <h1>Nieuw topic in het forum <q><%= @forum.naam %></q></h1> De new-action van de topics-controller (app\controllers\topics_controller.rb) wijzigen we naar:

def new
  @topic = Topic.new
  @forum = Forum.find(params[:id])
end

En de create-action wijzigen we naar:

def create
  @topic = Topic.new(params[:topic])
  @topic.datum = DateTime.now
  if @topic.save
    flash[:notice] = 'Topic was successfully created.'
    redirect_to :action => 'list', :id => @topic.forum_id
  else
    render :action => 'new', :id => @topic.forum_id
  end
end

Zo, als we nu een nieuw topic aanmaken, zal dit automatisch in het correcte forum geplaatst worden.

Je kan nu ook nog precies hetzelfde doen met de posts, maar dat is in principe volledig dezelfde procedure.
Als dat gelukt is heb je al een mooi basisforum ineengestoken op een heel korte tijd. Natuurlijk zit er nog niets in van authenticatie, maar je kan dit ook makkelijk verwezenlijken met bijvoorbeeld de gem login_generator

Besluit

Ruby on Rails is een prachtige technologie waarmee je in korte tijd heel mooie dingen kan ineensteken. De MVC-structuur van Rails kan je goed vergelijken met een 3-tier opbouw, wat toch ook een voordeel is.

Een nadeel aan Rails kan zijn dat je de Ruby syntax een beetje zal moeten leren en ook dat er nog niet veel hostingmaatschappijen zijn die dit momenteel al ondersteunen.

Rails staat zeker zijn mannetje tegen de 2 groten van deze tijd: PHP en ASP.NET en ik verwacht in de toekomst dat er veel gebruik van gemaakt zal worden.

Ook leuk om te weten is dat deze applicatie 143 lijntjes code bevat, waarvan we meer dan de helft nog niet eens zelf geschreven hebben. Je kan het aantal lijnen code vinden door het volgende commando in te geven in de commandoprompt in de root van je applicatie (D:\rails\forum): rake stats

Bronnen

http://www.rubyonrails.org/ http://en.wikipedia.org/wiki/Ruby_on_rails http://www.webwereld.nl/articles/38612 http://tweakers.net/nieuws/40363 http://www.onlamp.com/pub/a/onlamp/2005/01/20/rails.html http://www.onlamp.com/pub/a/onlamp/2005/03/03/rails.html