Sie sind auf Seite 1von 12

Einführung in Ruby on Rails

Seminararbeit FHNW 2006 Markus Stauffiger

In h alt sverzeic h n is

Inhaltsverzeichnis

2

0. Was ist Ruby on Rails?

3

1. Installation von Ruby

3

2. Beispiel Applikation

4

2.1 Problemstellung

4

2.2 Vorbereitung

4

2.3 Erste Erfolgserlebnisse

5

2.4 Was ist geschehen?

5

2.5 Weiter gehts! Her mit dem parttype

6

2.6 Beziehungen

6

2.7 Validierung

7

2.8 Benutzerverwaltung & Filter

8

2.9 Finishing

9

3. Ajax & Weitere Möglichkeiten

10

3.1 Ajax

10

3.2 Webservice

11

3.3 Unit Testing

11

4. Literatur

12

5. Fazit

12

6 Links

12

0. Was ist Ruby on Rails?

Ruby on Rails (Rails) ist ein Framework um auf Basis von Ruby Datenbank-gestützte Websites zu erstellen. Einfachheit und Effizienz sind dabei die zwei wichtigsten Grundsätze, ohne dabei auf moderne Methoden der Softwareentwicklung zu verzichten. MVC, Unit Tests und DRY (Don’t repeat yourself) sind beinahe nicht zu umgehen.

Aber ohne hier weiter alle Features von Ruby aufzuzählen, schreiten wir jetzt zur Tat und werden diese selbst erleben.

1. Installation von Ruby

Grundsätzlich kann Rails auf allen Plattformen die Rails unterstützen. Linux, Mac OS und Windows sind selbstverständlch mitdabei. Ich beschreibe hier kurz die Installation unter Windows:

Es gibt zwei Möglichkeiten Rails zu Installieren: Einen Komplettinstaller mit Ruby, Rails, Apache und mySQL oder einen One-Click Ruby Installer.

One-Click Ruby Installer: http://rubyinstaller.rubyforge.org

Ich verwende für das folgende Beispiel den Komplettinstaller.

Schritt 1

Download & Entpacken

Schritt 2

Doppelklicken von „Instant Rails“, Erscheinende Meldung bestätigen.

Schritt 3

In der Konsole ins entsprechende Rails-Verzeichnis wechseln, den Befehl „use_ruby“ eingeben.

Schritt 4

Testapplikation einrichten: Nun sollten wir uns im Verzeichnis ruby_apps befinden. Mit folgendem Befehl kann ein Beispielprojekt angelegt werden „rails start“.

Schritt 5

Nun wechseln wir in das neue Verzeichnis „start“ um dort den Ruby Webserver mittels „ruby script/server“ zu starten. Via http://localhost:3000 können wir nun unsere erste „Applikation“ begutachten.

2. Beispiel Applikation

2.1 Problemstellung

Für diesen Bericht verwende ich ein durchgehendes Beispiel. Im folgenden ist das Domainmodel des Projekts, es handelt sich dabei um „Parts“ welche einen Typ „Parttype“ haben.

Domänen-Modell

parts parttypes

parts

parts parttypes
parts parttypes
parts parttypes

parttypes

Applikationsscreenshot

Domänen-Modell parts parttypes Applikationsscreenshot 2.2 Vorbereitung Wir beginnen gleich mit der Erstellung des

2.2 Vorbereitung

Wir beginnen gleich mit der Erstellung des Gerüst für den ersten Teil, streng nach dem Dont- Repeat-Yourself (DRY) Ansatz von Rails.

Als erstes gilts ein Projekt anzulegen, dazu gehen wir in die Konsole, ins Rails-Verzeichnis, geben „use_ruby“ ein. Dabei wird lediglich der Umgebungspfad gesetzt und wir landen im „rails_apps“ Verzeichnis. Hierhin kommen alle Rails Projekte.

Ein neues Projekt legt man mit folgendem Kommando an:

rails cidb

Nun werden diverse Verzeichnisse mit einigen Dateien angelegt. Da wir gleich mit einer Datenbank beginnen wollen, müssen wir die Datenbank anlegen & unsere Applikation konfigurieren.

Als erstes legen wir daher mittels phpmyadmin (bei Instantrails dabei) oder direkt in der Konsole eine Datenbank „cidb“ an.

Die Datei config/database.yml erlaubt nun eine entsprechende Konfiguration. (Ich verwende RadRails, eine Eclipse-basierte IDE)

development:

adapter: mysql database: cidb_dev username: root password:

host: localhost

2.3 Erste Erfolgserlebnisse

Bis jetzt noch alles ganz trocken

3

Anlegen der Datenbank

Wir legen im Verzeichnis die Datei create_tables.sql mit folgendem Inhalt an. Den Befehl setzten wir als nächstes am einfachsten via phpmyadmin ab.

gleich gehts los!

CREATE TABLE parts ( id INT NOT NULL auto_increment, name VARCHAR(100) NOT NULL, label VARCHAR(100) NOT NULL, snr VARCHAR(100) NOT NULL, buy_date date NOT NULL, parttype_id int NOT NULL default '0', primary key(id)

)

2

Anlegen des Gerüsts für „part“ mittels Konsolenbefehl (im Verzeichnis rails_apps/cidb/)

ruby script/generate scaffold partpart

Dies generiert ein Model und einen Controller mit Namen “part”

1

Starten unseres Servers mittels folgendem Befehl (im Verzeichnis rails_apps/cidb/)

ruby script/server

Lift off

2.4 Was ist geschehen?

Als erstes haben wir eine Tabelle angelegt, per Default Modelname + „s“ als Pluralform. Ist von Rails so vorgesehen, kann jedoch angepasst werden.

Der zweite Schritt legt uns die notwendigen Dateien für eine CRUD (Create,Read,Update,Delete) Applikation an. Im Edit-Modus sieht man Feinheiten, wie Datums Auswahl. Da Rails streng nach dem MVC-Pattern arbeitet wurden dabei folgende Dateien angelegt:

app/controllers/part_controller.rb

Hier sieht man warum die Applikation überhaupt funktioniert, jede „def“ Zeile definiert eine Funktion welche bei entsprechende Aktion ausgeführt wird.

app/model/part.rb

Hier passiert noch kaum was, unsere Klasse erbt lediglich von der Klasse ActiveRecord. Dies ist ein „SubFramework“ von Rails. Es dient zur Anbindung an die Datenbank, und da wir uns an die Rails Namenskonventionen gehalten haben funktioniert dies auch einwandfrei. Wir werden mit dieser Klasse später noch arbeiten, mehr dann zu gegeben Zeitpunkt.

app/views/part/*

Hier sehen wir die unterschiedlichen Views welche wir für die Applikation verwenden.

Im letzten Schritt starten wir bloss noch den mitgelieferten Webserver Webbrick, dieser ist ideal zum Entwickeln, in einer Produktivumgebung sollte Rails jedoch mit Apache oder anderen unterstützten Webservern konfiguriert werden.

2.5 Weiter gehts! Her mit dem parttype

Mit der selben Vorgehensweise lassen wir uns von Rails ebenfalls den „part_type“ generieren.

SQL:

CREATE TABLE parttypes ( id INT NOT NULL auto_increment, name VARCHAR(100) NOT NULL, description text NOT NULL, price VARCHAR(100) NOT NULL, `comment` text NOT NULL, primary key(id)

)

Rails:

ruby script/generate scaffold parttype parttype

Hier gehts nun zur Applikation:

2.6 Beziehungen

Jetzt haben wir zwar zwei Module welche wir verwalten können, es fehlt jedoch die Beziehung. Diese können von Rails selbst bei Angabe von Foreign-Key-Constraints nicht automatisch aufgelöst werden, da sich eine 1:1 Beziehung und eine 1:N Beziehung nicht an diesen unterscheiden lässt.

Die 1:N Bezeihung von Part zu Parttype können wir (vrgl. wie bei Hibernate und/oder EJBs) mit einem Annotations-ähnlichen Ansatz erledigen, dazu editieren wir die beiden Klassen wie folgt:

app/models/part.rb

class Part < ActiveRecord::Base belongs_to :parttype end

app/models/parttype.rb

class Parttype < ActiveRecord::Base has_many :parts end

Dies bringt aber noch nicht viel, schliesslich müssen wir den entsprechenden Parttype noch auswählen können, dazu passen wir das entsprechende Formular an. Dazu fügen wir folgende Zeilen vor dem „<!--[eoform:part]-->“ ein

<p><label for="part_parttype_uid">Part type</label><br />

<%=

:name ) %> </p>

collection_select("parttype_id", "parttype_id", @parttype, :id,

Hier erhalten wir ebenfalls einen guten Überblick wie man mit Rails Formulare erzeugen kann. Rails stellt dazu eine Vielzahl von „Form-Helpern“ zur Verfügung, welche die Arbeit deutlich vereinfachen.

Den „collection_select“ füllen wir dabei mit „@parttype“ welche über den Controller alle Parttypes erhält. Der Kontroller wird dabei jeweils um eine einzelne Zeile erweitert (app/controllers/part_controller.rb)

def new @part = Part.new @parttype = Parttype.find(:all, :order => "name") end

def edit @part = Part.find(params[:id]) @parttype = Parttype.find(:all, :order => "name") end

def create @part = Part.new(params[:part]) @parttype = Parttype.find(:all, :order => "name")

2.7 Validierung

Das klappt ja mittlerweile ganz gut, wenn jedoch jemand auf die Idee kommt Parttypes ohne Namen zu erstellen, erscheinen in unserem Dropdown leere Zeilen oder mehrere Namen

kommen doppelt vor

sehr ärgerlich! Daher: Validierung muss her!

Wie man sich mittlerweile vorstellen kann, ist auch dies in nur einem Schritt erreichbar: Wir bearbeiten dazu das Model des Parts (app/models/project.rb)

class Part < ActiveRecord::Base belongs_to :parttype validates_presence_of :name validates_uniqueness_of :name end

2.8 Benutzerverwaltung & Filter

Selbstverständlich darf nicht jeder unsere Datenbank ansehen bzw. bearbeiten. Grundsätzlich verwenden wir dazu den Rails Filtermechansimus, vergleichbar mit Filter von Spring, Interceptoren etc.

Da wir die Benutzer auch gerne verwalten möchten, legen wir nach dem bekannten Schema eine

CREATE TABLE people ( id int NOT NULL auto_increment, username varchar(20) not null, password varchar(20) not null, primary key(id)

)

Tabelle an und erzeugen uns die CRUD-Funktionalität direkt mit Rails.

Erstellung des CRUD Funktionalität

ruby script/generate scaffold person admin

Testen

Ok, nun können wir einen Benutzer erfassen, z.b. admin/password. Geschützt ist jedoch noch nichts, dazu müssen wir den ApplikationsController (app/controllers/application.rb) anpassen. Da all unsere Controller von dieser Klasse erben, lässt sich so an zentraler Stelle die Authentifikation unterbringen. Sofern also irgend eine View aufgerufen wird, überprüft Rails ob eine Session mit einer Variablen vom Typ „person“ existiert.

class ApplicationController < ActionController::Base before_filter :authenticate, :except => [:login, :sign_on]

protected def authenticate unless session[:person] redirect_to :controller => 'part', :action => 'login'

end

end

end

Damit dies funktioniert braucht der Part-Controller (app/controllers/part_controller.rb) noch eine entsprechende „login“-Action, was folgendermassen gemacht wird:

def login

end

Jetzt benötigen wir noch eine View zu dieser Action (app/views/part/login.rhtml)

<%= form_tag :action => "sign_on" %> <p>Username:<br /><%= text_field 'person', 'username' %></p> <p>Password:<br /><%= password_field 'person', 'password' %></p> <%= submit_tag 'Login' %> <%= end_form_tag %>

Nun haben wir ein Problem

eingerichtetem Benutzer nicht anmelden, dazu benötigen wir im Part-Controller (app/controllers/part_controller.rb) noch eine entsprechende „sign-on“ Action:

wir sehen nur noch den Login-Screen, können uns aber trotz

def sign_on person = Person.find(:first, :conditions => ["username = BINARY ? AND password = BINARY ?",params[:person][:username], params[:per- son][:password]]) if person session[:person] = person redirect_to :action => 'list'

else

render :action => 'login'

end

end

Und schon habe wir in ca. 10min einen Authentifikationsmechanismus inkl. Administrationmodul erstellt.

2.9 Finishing

Ein wenig mühsam ist der manuelle Wechsel von „/part“ zu „/parttype“ scho, schliesslich wollen wir ja eine Webapplikation machen und nicht bloss die „Generator“-Fähigkeiten von Ruby demonstrieren.

Als Haupttemplate kann man dazu app/views/layouts/application.rhtml anlegen. Diese Datei wird nun für jede View als Basis verwendet (sofern nicht „modelname“.rhtml im diesem Verzeichnis liegt).

Des weiteren gibt es so genannte „Partial Views“ welche es erlauben, mehrfach verwendete Elemente in einzelne Dateien auszulagern. In unserem Fall bietet sich bspw. das Menu an. Da das Menu bei jedem Model anderst aussieht, können wir in den Views (z.B. app/views/part/_menu.rhtml) die Datei _menu.rhtml anlegen. Damit das Menu nun auf jeder Seite erscheint, müssen wir es in der application.rhtml Datei noch includieren:

<%= render :partial => "menu" %>

3. Ajax & Weitere Möglichkeiten

3.1 Ajax

Für diejenigen dies noch nicht kennen: Ajax ermöglich den (XML) Datenaustausch zwischen Browser und Server, so dass für Änderungsdarstellung nur der wirklich benötigte Code geladen werden muss.

Rails biete standardmässig Ajax-Funktionalität an, in unserer Teileverwaltung sollte man nun mittels Drag&Drop die Reihenfolge der Parttypes ändern können.

Dazu müssen wir die Javascript-Bibliotheken in unserem Application.rhtml inlcudieren, dies geschieht mittels:

<%= javascript_include_tag :defaults %>

Dazu kommen kleine Veränderungen bei der Auflistung:

- Auflistung der Parttypes nicht mehr in Tabelle sondern in z.b. „<li>“ Tags

- Aktivieren der Sortierung

<ul id="list"> <% for parttype in @parttypes %> <li id="parttype_<%= parttype.id %>”> <%=h parttype.send('name') %>

</li> <% end %>

</ul> <%= sortable_element('list', :url => {:action => :order}) %>

Die Parttype-Tabelle erhält eine neue Spalte position:

ALTER TABLE parttypes add column position int;

Nun muss unser Model noch wissen in welcher Spalte die Sortierung steht, dazu fügen wir in die Datei app/models/parttype.rb

class Parttype < ActiveRecord::Base has_many :parts, :order => :position end

Als letzter Schritt müssen wir noch den Controller anpassen, da dieser ja auf einen entsprechenden Event reagieren soll:

def order pos = 1 params[:list].each do |parttype_id| parttype = Parttype.find(parttype_id) parttype.position = pos parttype.save pos += 1 end render :nothing => true

end

3.2 Webservice

Webservices & Webservice Clients lassen sich ähnlich komfortabel erstellen wie die übrigen Elemente von Rails.

3.3 Unit Testing

Rails kann für jeden der MVC Elemente separate Unit-Tests durchführen, einem testgetriebenen Entwicklungsansatz steht somit nichts im Wege.

4. Literatur

Die Grundlagen für diesen Seminarbericht liefert das Buch “Rapid Web Development mit Ruby on Rails” von Rafl Wirdemann und Thomas Baustert.

Das Buch bietet dem Web-vertrautem Leser einen schnellen und interessanten Einstieg in Rails, ich kann es daher nur empfehlen.

5. Fazit

Als täglicher Anwender von php war ich erstaut wie alltägliche Aufgaben von Rails einfach erledigt wurden, ohne dass man auch nur eine Zeile Code dafür schreiben musste. Weitere Features lassen sich mit minimalstem Aufwand in realisieren: Validierung, Beziehungen, Ajax etc. um nur einige Vorteile zu erwähnen.

Als ich mit dem Spring Framework Erfahrungen sammeln konnte, dachte ich php sei simpel. Meine Fortschritte in Rails zeigten jedoch, dass es noch viel einfach geht, ohne dabei auf moderne Software-Engineering Ansätze wie MVC, Unit Tests etc. zu verzichten.

Ich werde in Zunkuft sicherlich Rails für Kundenprojekte einsetzten, ich bin schon ganz gespannt wie sich Rails mit einere komplexeren Aufgabenstellung bewährt, denn nur so wird man die (möglichen) Schwachstellen erkennen können.

Als Einstieg empfehle ich entweder obenstehendes Buch oder eines der zahlreichen Online- Tutorials. Es scheint eine grosse Community rund um Rails zu existieren, was sicherlich den Einstieg sowie das Lösen von „Knacknüssen“ wesentlich erleichtern wird.

6 Links

Empfohlen

Instant Rails

Komplettpaket zum direkt loslegen

Rails Homepage

Ausführliche Rails Homepage

RadRails IDE

Eclipse-basierte IDE für Rails

Weitere Links

Ruby Installer