Der Unterschied liegt im Detail: Ruby on Rails 3.0
Als Ruby on Rails (kurz: Rails) im Juli 2004 das erste Mal der Öffentlichkeit vorgestellt wurde, ahnte noch niemand, welch großen Einfluss das Framework sowie dessen Architektur und Philosophie auf die Web- und Softwareentwicklung nehmen würde.
Heute findet sich ein mehr oder weniger großes Stück Rails in jedem modernen Web-Framework. Paradigmen wie „Don’t repeat yourself“ oder „Convention over configuration“ gelten als inoffizielle Standards der modernen Webentwicklung. Ruby on Rails hat sich seither stetig weiterentwickelt und Webapplikationen auf dem „Rails-Way“ zu erstellen geht heute einfacher, schneller und besser als je zuvor.
Dabei ist dieser goldene, direkte Weg aber auch gleichzeitig einer der größten Kritikpunkte des Frameworks. Denn Abweichungen in Form der Nutzung anderer ORMs, Test- oder JavaScript-Bibliotheken sind zwar möglich, jedoch stets mit dem Patchen des Framework-Kerns verbunden. Eine öffentliche API wurde bislang schmerzlich vermisst.
Im Dezember 2008 wurde dieser Makel durch das Core-Team aufgegriffen, um ihn mit Rails 3.0 zu beseitigen. Dabei sollte sich die neue Version am modularen Aufbau des einstigen Konkurrenten Merb orientieren, jedoch die eigene Einfachheit und Schnelligkeit beibehalten. Seitdem arbeitet das Rails-Core-Team zusammen mit der Community an Version 3, aktuell (Stand April 2010) ist die dritte Beta-Version erschienen. Diese ermöglicht einen ersten Blick auf die Änderungen und neuen Funktionalitäten.
Die folgende Anwendung zeigt, wie man mit Rails 3 eine neue Applikation erstellt und worin die Unterschiede und Verbesserungen zur aktuell verfügbaren Version 2.3 liegen.
Erstellen einer neuen Applikation
Um Rails 3 nutzen zu können, müssen zunächst Ruby (Version 1.8.7 oder höher) und RubyGems (Version 1.3.6) auf dem Rechner vorhanden sein. Die aktuelle Beta-Version von Rails 3 lässt sich dann einfach von der Konsole mit dem folgenden Befehl installieren:
sudo gem install rails ––pre
Listing 1
Momentan gibt es noch einige Probleme beim Parallel-Betrieb von Rails 2 und 3. Es wird deshalb empfohlen, der Anleitung von Ryan Bates zu folgen und RVM (Ruby Version Manager) für das Betreiben der Rails 3-Beta zu nutzen [1]. Durch Ausführen des Befehls
rails t3n
Listing 2
wird eine neue Applikation mit dem Namen „t3n“ angelegt und automatisch die zugehörige Verzeichnisstruktur im Ordner „t3n“ erzeugt. An dieser hat sich gegenüber den Vorgängerversionen nur wenig geändert. Neu hinzugekommen sind jedoch zwei wichtige Dateien für die Konfiguration der Anwendung sowie deren Abhängigkeiten zu anderen Bibliotheken (RubyGems). Diese Abhängigkeiten werden nun global vom Bundler-Gem [2] behandelt und in der Datei „Gemfile“ angegeben. Mittels „bundle install“ lassen sich auf dem Produktionsserver schließlich alle benötigten Bibliotheken automatisch installieren.
In der zweiten wichtigen Datei, „config/application.rb“, werden projektspezifische Konfigurationen angegeben.
module T3n class Application < Rails::Application ... config.generators do |g| g.orm :active_record g.template_engine :erb g.test_framework :rspec end end end
Listing 3
Listing 3 zeigt, wie in der neuen Konfiguration gezielt einzelne Komponenten für das Framework ausgewählt werden können. Dies sorgt auch dafür, dass die jeweiligen Generatoren bei der Erstellung von Models und Controllern verwendet werden. In diesem Falle würden für die Tests RSpec- und für die Views ERB-Dateien erzeugt.
Apropos Generatoren: Mit dem Scaffold-Generator ließe sich nun fast der gesamte weitere Code für Model, Controller und Views unserer kleinen Anwendung automatisch generieren. Darauf wird jedoch an dieser Stelle verzichtet. Stattdessen wird der manuelle Weg bevorzugt. Weiterführende Informationen zum Scaffolding mit Rails 3 finden sich in einem Artikel von Ben Scofield [3].
ActiveRecord in Rails 3
ActiveRecord ist wie in allen vorigen Rails-Versionen das Standard-ORM und soll auch in diesem Beispiel Verwendung finden.
Auch bei ActiveRecord haben sich in Version 3 einige Dinge weiterentwickelt: So werden Generatoren in Rails 3 nicht mehr mit „script/generate“ aufgerufen, sondern dies alles liegt nun unter dem Keyword „rails“. Mit dem folgenden Konsolen-Befehl lässt sich ein neues Model mit dem Namen „Post“ erstellen.
rails generate model Post title:string body:text published:boolean
Listing 4
Der Generator erstellt zum einen das Model unter „app/models/post.rb“, gleichzeitig werden auch die passenden Datenbank-Migrationen im Ordner „db/migrate/“ erzeugt. Mit den folgenden Befehlen lässt sich die Datenbank erstellen und anschließend auf den aktuellen Stand migrieren:
rake db:create # Falls noch keine DB existiert rake db:migrate
Listing 5
Einer der vielen Vorteile von ActiveRecord ist nach wie vor, dass das ORM zur Laufzeit über die Datenbanktabellen reflektiert und die vorhandenen Spalten automatisch auf Attribute mappt. So müssen in dem Post-Model nur noch Dinge wie Validierungen und Methoden zum Datenzugriff definiert werden (s. Listing 6).
Bei beiden Funktionalitäten hat es in Rails 3 einige Anpassungen gegeben: Die Syntax für die Validierungen ist konsistenter geworden und ermöglicht es, mehrere Validierungen an einer Stelle zu definieren. Außerdem basiert das neue Interface für den Datenzugriff nun auf einer relationalen Algebra [4], was ebenfalls eine konsistentere Syntax und eine vereinfachte Definition von Zugriffsmethoden (scopes) ermöglicht [5].
class Post < ActiveRecord::Base validates :title, :presence => true, :maximum => 60 scope :published, where(:published => true) end
Listing 6
Neben diesen sofort ersichtlichen Dingen hat sich „unter der Haube“ ebenfalls eine Menge getan. So steht als Model-Schnittstelle in Rails nun die ActiveModel-API zur Verfügung. Diese Schnittstelle sorgt dafür, dass sich andere ORMs einfacher als bisher an Rails andocken und ActiveRecord komplett ersetzen können. Auch können andere Persistenzschichten jetzt gezielt bestimmte Funktionen, wie Validierungen oder Callbacks, übernehmen und müssen keine eigenen Lösungen anbieten. Schon vor dem offiziellen Release von Rails 3 gibt es bereits erste Bibliotheken, die die ActiveModel-API nutzen. Ein Beispiel hierfür wäre „Supermodel“ [6].
Controller und Routing
Auch in der Steuerschicht zwischen Models und Views hat es in der neuen Version einige Änderungen gegeben. Erstellen lässt sich ein neuer Controller wiederum mit einem Rails Generator:
rails generate controller posts
Listing 7
Unter „app/controllers/posts_controller.rb“ wird der neue Controller abgelegt. Generell hat sich am Aufbau der Controller nur wenig geändert und Rails baut nach wie vor stark auf der REST-Architektur auf. Allerdings gibt es in Rails 3 nun die Möglichkeit, beim Standard-Verhalten der Controller-Methoden auf eine vereinfachte Schreibweise zurückzugreifen.
Musste man in Rails 2 noch explizit den Render-Prozess für die unterschiedlichen Ausgabeformate (beispielsweise HTML, JSON) anstoßen, so lässt sich in Rails 3 mittels „respond_to“ global definieren, welche Formate von dem Controller ausgeliefert werden sollen. In den jeweiligen Methoden kann dann das Rendern mit einem einfachen „respond_with“ zusammengefasst werden. Dieses ist eines der zahlreichen Features, die von Merb übernommen wurden. Hintergründe zu der vereinfachten API erklärt David Heinemeier Hansson auf seiner Website [7].
class PostsController < ApplicationController respond_to :html, :xml, :json def index respond_with(@posts = Post.all) end end
Listing 8
Damit der Controller über eine URL im Browser erreichbar ist, muss dieser noch in der Datei „config/routes.rb“ als Route eingetragen werden. In Rails 3 wurde die DSL zur Definition der Routes komplett überarbeitet [8], was vor allem bei komplexeren Projekten für eine erhöhte Übersicht sorgt.
T3n::Application.routes.draw do |map| resources :posts end
Listing 9
Da der Posts-Controller ein einfacher REST-Controller ist, reicht es aus, diesen als einfache Ressource in den Routes zu deklarieren.
Der neue Router, der komplett auf die Ruby-Webserver-Schnittstelle Rack [9] aufsetzt, ermöglicht noch einiges mehr. Da quasi jede Methode in einem Controller eine eigene Rack-Anwendung ist und von Rails so behandelt wird, können nun auch andere Rack-basierte Frameworks in Rails eingebunden werden.
So lässt sich beispielweise, anhand einer kleiner Twitter-Anwendung, das Ruby-Mikro-Webframework Sinatra auf diese Weise vollständig in eine Rails-Anwendung integrieren [10]. Eigentlich schon für Version 3.0 angekündigt, soll mit einem der nachfolgenden Releases auch das „Mounten“ von kompletten Rails-Anwendungen ermöglicht werden.
Sicherheit und aufgeräumte Views
Die Schnittstelle zum Nutzer wird durch die Views bereitgestellt. Beim Anlegen des Controllers wurde unter „app/views/posts“ automatisch ein View-Verzeichnis für den Posts-Controller erstellt. Dort lässt sich für die Index-Action des Controllers eine Datei „index.html.erb“ anlegen, in der dann auf die Instanzvariablen des Controllers zugegriffen werden („@posts“) und die Ausgabe erfolgen kann.
<html> ... <body> <% for post in @posts %> <%= post.title %> <% end %> </body> </html>
Listing 10
Ruby on Rails bot schon immer eine ganze Reihe an Mechanismen zum Schutz vor Sicherheitslücken. Doch vor allem in den Views konnte man leicht vergessen, eine Nutzereingabe explizit HTML zu enkodieren, was zu einer potenziellen Sicherheitslücke für Cross-Site-Scripting führen kann. Rails 3 macht dem Entwickler das Leben nun etwas leichter und konvertiert alle Zeichenketten implizit in ein sicheres Format. Um nur den eigentlichen Wert auszugeben, kann man die Methode „html_safe“ verwenden, um ihn in seinem Ursprungsformat auszugeben.
Eine weitere Neuerung in Rails 3 ist die Nutzung von „Unobtrusive JavaScript“. Bisher wurde dem Entwickler durch die vielen Helper-Methoden, vor allem in Verbindung mit Ajax, eine Menge Arbeit abgenommen. Dafür musste dieser jedoch mit Inline-JavaScript im HTML-Code leben. In Rails 3 ist der benötigte JavaScript-Code komplett in externe Dateien ausgelagert und somit von der Präsentation getrennt. Durch diese Trennung ist es wesentlich einfacher, andere JS-Bibiotheken wie jQuery oder mootools zu verwenden. Die Metainformationen zu den JavaScript-Funktionen werden in den HTML5-konformen Data-Attributen festgehalten.
Evolution der einstigen Revolution
Nach dem kleinen Rundgang durch eine Anwendung in Rails 3 lässt sich feststellen, dass die sichtbaren Unterschiede zunächst recht marginal ausfallen. Einige Module haben eine schönere und einfache DSL spendiert bekommen. Die generelle Funktionsweise ist jedoch weitestgehend gleich geblieben. Alles wirkt noch ein bisschen besser durchdacht und mit den gut ausgewählten Standards (ActiveRecord als ORM, Prototype/Scriptacolous als JavaScript-Bibliotheken) kann man direkt auf dem „Rails-Way“ durchstarten.
Im Detail hat sich jedoch eine Menge getan, auch wenn das im Artikel nur an manchen Stellen wirklich ersichtlich ist. Durch die ActiveModel-API können andere ORMs nun einfacher und vor allem standardisiert an Rails andocken. Bereits vor dem Release von Rails 3 gibt es eine Reihe an alternativen Frameworks, die man an Stelle von ActiveRecord nutzen kann. Vor allem die vielen Bibliotheken für NoSQL-Datenbanken (CouchDB, MongoDB etc.) werden davon profitieren. Auch für die Erweiterung von Rails selbst wurde eine öffentliche API eingeführt beziehungsweise die vorhandene ausgebaut. Rails-Plugins und Gems können sich nun an verschiedenen Stellen im Boot-Prozess einklinken und so Einfluss auf das Framework nehmen. Weiterhin sorgt der modulare Aufbau dafür, dass man sich theoretisch auch sein eigenes kleines Web-Framework aus den Rails-Komponenten zusammenbauen kann.
Yehuda Katz zeigt in einem Blog, wie man Controller-Funktionalitäten deaktiviert, um die Anwendung zu beschleunigen [11].
Ein Manko, das diese strukturellen Änderungen mit sich bringt, ist die nicht mehr 100%-ige Abwärtskompatibilität zu Vorgängerversionen. In Rails 3 werden einige „alte Zöpfe“ zunächst als veraltet markiert, in der Folgeversionen 3.1 jedoch gänzlich entfernt. Die Community hat sich diesem Thema aber bereits angenommen und eine Plattform online gestellt, auf der Rails-3-kompatible Plugins und Gems aufgelistet werden [12].
Abschließend lässt sich sagen, dass Rails 3 wohl nicht das Rad, dafür aber große Teile von sich selbst neu erfindet. Die vielen kleinen Verbesserungen machen das Arbeiten mit dem Framework noch einfacher und schneller. Und vor allem die großen strukturellen Änderungen sorgen dafür, dass Rails 3 wesentlich flexibler wird und sich bei Bedarf noch besser an die Anforderungen eines Projekts anpassen lässt.