<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
   <channel>
      <title>/blog/wvk</title>
      <link>http://innoq.com/blog/wvk/</link>
      <description>$ cat `grep -eli &quot;ruby|rails|apache|linux&quot; /var/brain/wvk` &gt; /blog/wvk 2&gt;&amp;1</description>
      <language>en</language>
      <copyright>Copyright 2008</copyright>
      <lastBuildDate>Mon, 05 May 2008 02:58:49 +0100</lastBuildDate>
      <generator>http://www.sixapart.com/movabletype/</generator>
      <docs>http://blogs.law.harvard.edu/tech/rss</docs> 

            <item>
         <title>Das &quot;Geheimnis&quot; von deklarativen Assoziationsdefinitionen</title>
         <description><![CDATA[Da ich nunmehr in zwei verschiedenen Sprachen mich mit dem Thema der deklarativen Art der Definition von Assoziationen zwischen Klassen beschäftige, schien es mir sinnvoll, darüber an dieser Stelle mal etwas zu schreiben. 

Erstmal: was meine ich mit diesem toll klingenden Konzept überhaupt? Ich meine damit das, was jeder Rails-Mensch kennt:

    class Foo < ActiveRecord::Base
      has_many :bars
      belongs_to :baz
    end

oder, mit dem in meinem letzten Post beschriebenen JS-Framewörkchen:

    var Foo = ActiveResource.inherit({
      has_many: {
        bars: {}
      }
      has_one: {
        baz: {}
      }
    });

Was man erwartet, ist dass ein Aufruf von `foo.bars()` die Liste aller zu `foo` gehörenden `Bar`-Instanzen liefert. Das zu bewerkstelligen ist in jeder Scriptsprache, die so etwas wie eine `eval()`-Methode oder gar ein ausgefeiltes Mataprogrammier-Konzept wie Ruby kennt, an sich relativ einfach. Das Rezept (am Beispiel von `has_many`):

 - man definiere eine Methode, welche die `find`-Methode der assoziierten Klasse mit einem Kontext definierenden Argument wie "für foo_id=self.id" auf. Ich schreibe das bewusst so allgemein, weil die konkrete Implementierung stark von der zu Grunde liegenden Persistenz abhängt -- es könnte (im Falle von ActiveResource) die Generierung einer URL mitsamt eines HTTP-Requests, oder (im Falle von ActiveRecord) die Generierung einer SQL-Query oder einer Suche-in-Textdatei-Methode oder oder... sein.
 - man definiere eine *Klassenmethode* namens `has_many`, die als Argument mindestens den Namen der Assoziation entgegennimmt (und daraus ggf. den Klassennamen der assoziierten Klasse herleitet)
 - man *generiere* eine Methode mit dem Namen des an `has_many` übergebenen Arguments (z.B. `foos`), die die erstgenannte Methode kapselt. In Javascript kann man z.B. mit sowas wie `eval('Foo.prototype.' + association_name + '=function(){....}')` arbeiten. In Ruby würde man die Methode eher gleich mittels `define_method` dynamisch generieren (`define_method association_name do ... end`).
 - man freue sich, dass bei einem Aufruf von `foo.bars()` nun das gleiche zurückgegeben wird, wie es (im Falle von RoR) bei `Bar.find(:all, :conditions => "foo_id=#{foo.id}")` der Fall wäre.

Aaaaber: das kann doch noch nicht der ganze Zauber gewesen sein? Und in der Tat, das ist erst ein kleiner, naiver Anfang. Wer Rails genauer kennt, weiß dass auch Konstrukte wie `foo.bars.find_by_name_and_trallalla()` ohne weiteres möglich sind. Dabei ist diese `find_by...`-Methode nicht etwa eine Methode der zurückgegebenen Collection (ich nenne das mal so, weil es je nach Sprache ein Array, ein Hash oder sonst eine iterierbare Objektsammlung sein kann), sondern wenn dann eine Klassenmethode von (in diesem Falle) `Bar`. In A Nutshell: Was auch immer beim Aufruf von `foo.bars()` zurückgegeben wird, es implementiert sowohl die Schnittstelle einer Collection (Array,...) als auch der Klasse, zu der die erwarteten Objektinstanzen gehören. (Genau genommen stimmt das nicht 100%ig, aber an dieser Stelle reicht diese Annahme).

Der geneigte Leser möge sich einstweilen den Rails-Code zu Gemüte führen und dabei feststellen, dass `foo.bars()` ein "Association Proxy"-Objekt zurückliefert. Dieses Objekt beinhaltet sämtliche Informationen darüber, wie die beiden Klassen zueinander in Beziehung stehen, wie die Instanzen der assoziierten Klasse geholt werden können und stellt Methoden bereit, um auf diese wie in einem Array zuzugreifen. Etwas genauer gesprochen erstellt die `has_many`-Methode ein Objekt, in dem die Informationen zu der Assoziation zwischen den Klassen gehalten wird und beim Aufruf der entsprechenden Objektmethode (`foo.bars()`) wird ein Objekt mit Informationen zu den *Instanzen* der referenzierten Klasse erstellt und zurückgegeben.

Mit dieser Information im Hinterkopf und etwas Geschicklichkeit ist es relativ einfach, miteinander in Beziehung stehende Resourcen jeder Art umzusetzen. Die Details *wie* man innerhalb des einen Objektes an das jeweils andere Objekt heran kommt, können hinter einer einheitlichen Schnittstelle (die des "Association Proxies") gekapselt werden. Somit ist es dann auch wenig umständlich, z.B. in RoR ActiveRecord- und ActiveResource-Objekte miteinander zu verknüpfen, über die gleiche deklarative Syntax wie man ActiveRecord-Objekte untereinander verknüpft. Ich arbeite gerade noch an einer halbwegs vollständigen, jedenfalls aber brauchbaren Implementierung dafür, denn ich sehe nun schon bald eine Handvoll Projekten, wo das zumindest Hilfreich wäre (Stichwort: Anwendung mit Benutzerverwaltung in einer anderen Anwendung, Kommunikation über HTTP/XML). Sobald das veröffentlichungswürdig ist, wird es selbstverständlich hier erscheinen.
]]></description>
         <link>http://innoq.com/blog/wvk/2008/05/das_geheimnis_von_deklarativen.html</link>
         <guid>http://innoq.com/blog/wvk/2008/05/das_geheimnis_von_deklarativen.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">Coding</category>
        
        
         <pubDate>Mon, 05 May 2008 02:58:49 +0100</pubDate>
      </item>
            <item>
         <title>Javascript + ActiveRecord + ActiveResource</title>
         <description><![CDATA[Dieses Wochenende stand wieder einmal ganz im Zeichen des freien Programmierens und ich muss sagen, dass ich mit den Ergebnissen doch ganz zufrieden bin. 

Der Hintergrund: Ich hatte schon länger ein angefangenes Projekt mit unter anderem einem vollständig in JavaScript implementierten Verfügbarkeitsplaner für vermietete Gegenstände (siehe Bild).

<a href="http://innoq.com/blog/wvk/snap17.png"><img alt="snap17.png" src="http://innoq.com/blog/wvk/snap17-thumb.png" width="350" height="244" /></a>

Die Implementierung dieses Planers umfasste rund 800 Zeilen Code, im wesentlichen war das eine gigantische Planer-Klasse und zwei kleinere, jeweils für die Repräsentation eines vermieteten Gegenstandes sowie dessen (Nicht-)Verfügbarkeitszeiträumen. Das alles war nicht sonderlich aufgeräumt und insbesondere was die Verwendung von Event-Handlern betraf alles andere als einfach erweiterbar. Deswegen sollte das neu geschrieben werden.

Die Vorarbeit: Am Samstagmorgen hatte ich "eben schnell" das in PHP geschriebene serverseitige Backend neu in Rails implementiert und dadurch auch eine schöne REST-Schnittstelle erhalten. Anschließend ging es darum, die serverseitigen Ressourcen 1:1 auf Clientseite abzubilden. Rails bietet hervorragende Voraussetzungen dazu: im Controllercode erweitert man seine `respond_to`-Blöcke einfach um ein `format.json { render :text => @obj.to_json }`.Statement. Dann kriegt der Client beim Aufruf von beispielsweise /clients/2.json die Repräsentation eines Client"-Objektes als JSON (JavaScript Object Notation) geliefert, was sofort evaluiert werden kann und dann als Javascript-Object zur Verfügung steht. Aber: was ist mit Assoziationen? Was mit dynamischem Nachladen von Objekten? Objekt-Caching etc.?

Der Plan: Also ward die Idee geboren, eine Art Mischung aus ActiveRecord und ActiveResource in Javascript zu implementieren. das <a href="http://www.prototypejs.org">prototype.js</a>-Framework bietet eine hervorragende Grundlage für solche Unterfangen, und ist mit seiner (nicht ganz zufälligerweise) an die RoR-Idiome angelehnte Namensgebung auch sehr angenehm zu verwenden. Das Ziel sollte nun sein, mit Hilfe von prototype.js ein kleines Framework zu schreiben, eine ähnlich minimalistische Klassendefinition erlauben würde wie ActiveRecord bzw, ActiveResource, inklusive der Generierung von Methoden zur Handhabung der Assoziationen.

Um eine lange Geschichte etwas zu kürzen, werde ich an dieser Stelle nicht konkret auf die Implementierung der ganzen Geschichte eingehen, sondern das in einem späteren Post tun. Hier erstmal ein Beispiel:

    // ActiveResource.inherit ist die "magische" Methode, die jede Menge Code generiert...
    var Trailer = ActiveResource.inherit({
     // ein paar Assoziationen:
      has_many: {
        'rental_periods': {},
        'occupations': {
          resource: 'occupation_dates',
        }
      },
      has_one: {
        'owner': {
          'class_name': 'TrailerOwner',
          'resource': 'people'
        }
      },
      // der Name der Ressource auf dem Server
      resource: 'trailers'
    });

Folgende Methoden stehen nun zur Verfügung:

    // holt sich das Trailer-Objekt (synchron) mit der ID 'id' und schreibt es nach {tr}
    var tr  = Trailer.findOne(id);
    // holt sich alle Trailer-Objekte (synchron) vom Server und schreibt sie nach {trs}
    var trs = Trailer.findAll();
    // holt Trailer {id} asynchron vom Server und übergibt das Resultat der Callback-Methode
    Trailer.findOne(id, callback);
    // dito für alle Trailer-Objekte
    Trailer.findAlll(callback);
    // liefert nach obiger Definition "/trailers"
    var url = Trailer.resource_url();
    // liefert nach obiger Definition "/trailers/{id}"
    var url = Trailer.element_url(id);
    // liefert nach obiger Definition "/trailers/{trailer_id}/rental_periods"
    var url = tr.rental_periods_url();
    // liefert nach obiger Definition "/trailers/{trailer_id}/rental_periods/{id}"
    var url = tr.rental_period_url(id);
    // liefert nach obiger Definition "/trailers/{trailer_id}/occupation_dates/{id}"
    var url = tr.occupation_url(id);
    ...
    // holt das OccupationDate-Objekt mit der ID {id}
    var oc = tr.occupation(id);
    // holt das Owner-Objekt
    var ow = tr.owner();
    ...

Alle Objekte, die (synchron oder asynchron) vom Server geholt werden, werden in einem internen Cache zwischengespeichert. Momentan greift der Cache nur beim lesen von Einzelobjekten, sprich ein Aufruf von `Trailer.rental_periods()` würde immer einen HTTP-Request an den Server schicken. Aber daran wird noch gearbeitet :)

Auch ist das Speichern von Objekten noch nicht möglich, aber die Implementierung der Funktionalität dürfte nur unwesentlich mehr als 30 Minuten in Anspruch nehmen...

Die mittels `ActiveResource.inherit()` generierte "Klasse" (Javascript kennt ja keine wirklichen Klassen, sondern arbeiten Prototyp-basiert) kann ohne weiteres mit der von prototype.js bereitgestellten Methode `Object.extend()` um weitere Methoden erweitert werden. Auch kann die "Vererbungs"-Methode `Class.create(Elternklasse, Kindsklasse)` angewendet werden. (Genau genommen tut ActiveRecord.inherit() genau dies: Es erstellt eine neue Kindsklasse mit `Class.create(ActiveRecord, MeineKlasse)` und erweitert MeineKlasse mit den diversen assoziationsbezogenen Methoden). Es ist auch möglich, Kindsklassen von einer von ActiveResource erbenden Klasse zu erstellen und diese wiederum mit Assoziazionsdefinitionen zu versehen. Allerdings nicht mit `Class.create()`, sondern wiederum mit `ActiveResource.inherit()`:

    var Trailer = ActiveResource.inherit({
      resource: 'trailers'
      has_many: {...},
      has_one: {...},
    });

    var TruckTrailer = ActiveResource.inherit(Trailer, {
      resource: 'truck_trailers',
      has_many: {...}
    });

Es ist theoretisch sogar möglich, beliebige "Klassen" mit der ActiveResource-Funktionalität "nachzurüsten":

    var Person = Class.create({...});
    var Person = ActiveResource.inherit(Person, {...definitionen der Ressourcen...});

Aber das ist eher eine akademische Überlegung, getestet hab ich das nicht ;-)

Den Quelltext findet ihr, meine werten Leser, hier: <a href="http://innoq.com/blog/wvk/active_resource.js">active_resource.js</a>. In einem nächsten Post erzähle ich dann mehr zur internen Funktionsweise des Codes. Stay tuned!
]]></description>
         <link>http://innoq.com/blog/wvk/2008/04/javascript_activerecord_active.html</link>
         <guid>http://innoq.com/blog/wvk/2008/04/javascript_activerecord_active.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">Coding</category>
        
        
         <pubDate>Mon, 14 Apr 2008 19:28:56 +0100</pubDate>
      </item>
            <item>
         <title>Eine Sorge weniger! -- und die nächste folgt sogleich.</title>
         <description><![CDATA[Die Zeit des Schweigens ist vorbei, die Diplomarbeit ist abgegeben und nun ist wieder viel Zeit für anderes. Natürlich wird die Entwicklung von Consolvix nicht stillstehen und genau genommen hat sich in der Hinsicht seit letzten Mittwoch auch wieder etwas getan. Dieses "etwas" hat hauptsächlich mit der Benutzeroberfläche zu tun, damit am Freitag im Kolloquium auch alle was Schönes zu sehen bekommen werden ;-)

Des Weiteren hab ich endlich mal Zeit gefunden, zusammen mit <a href="http://innoq.com/blog/phaus">Philipp</a> den endlich eingetroffenen Server aufzusetzen. Die Kiste ist handlich und fast schon schnuckelig:

<a href="http://innoq.com/blog/wvk/img_1739.html" onclick="window.open('http://innoq.com/blog/wvk/img_1739.html','popup','width=600,height=450,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false"><img src="http://innoq.com/blog/wvk/img_1739-thumb.jpg" width="300" height="225" alt="" /></a>

<a href="http://innoq.com/blog/wvk/img_1749.html" onclick="window.open('http://innoq.com/blog/wvk/img_1749.html','popup','width=600,height=450,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false"><img src="http://innoq.com/blog/wvk/img_1749-thumb.jpg" width="300" height="225" alt="" /></a>

<a href="http://innoq.com/blog/wvk/img_1758.html" onclick="window.open('http://innoq.com/blog/wvk/img_1758.html','popup','width=600,height=450,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false"><img src="http://innoq.com/blog/wvk/img_1758-thumb.jpg" width="300" height="225" alt="" /></a>

Doch wehe, man schaltet das Gerät ein -- die dann aufheulenden Lüfter lassen ein gewisses Luftalarm-Ambiente aufkommen... Dafür ist die Kiste mit ihrem 1.8 GHz C2D und 4GB RAM ganz schön flott und mittlerweile laufen auch schon ein paar virtuelle Maschinen unter Xen darauf. Allerdings hat es die Kombination Xen + Netzwerk in sich, ich hoffe dass wir die auftretenden Probleme bald gelöst bekommen (dazu vielleicht später mehr).

Und ja, richtig geraten: Consolvix soll dereinst genau diesen Server administrierbar machen. Entsprechend wird eine der nächsten Erweiterungen von Consolvix eine Oberfläche für die ganzen xm-Scripte und Xen-Tools-Befehle sein, damit Kunden dann auch ihre eigenen VMs hochfahren, neu starten etc. können. 

Stay tuned!]]></description>
         <link>http://innoq.com/blog/wvk/2008/03/eine_sorge_weniger_und_die_nac.html</link>
         <guid>http://innoq.com/blog/wvk/2008/03/eine_sorge_weniger_und_die_nac.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">Philosophisches und anderer Schmalz</category>
        
        
         <pubDate>Mon, 24 Mar 2008 23:18:24 +0100</pubDate>
      </item>
            <item>
         <title>Ein Paar Dia-Gramm</title>
         <description><![CDATA[OK, diese Diagramme wurden nicht mit Dia erstellt, sondern mit Umbrello. Aber nachdem <a href="http://innoq.com/blog/phaus">Philipp</a> schon solch schöne UML-Bildchen online gestellt hat, muss ich natürlich nachziehen ;-)

Das folgende Diagramm fasst noch einmal bildlich zusammen, was ich in <a href="http://innoq.com/blog/wvk/2008/01/verdeckte_transaktionen.html">einem anderen Post</a>  zum Ablauf einer Transaktion beschrieben hatte. Übrigens wäre ich noch immer SEHR dankbar, wenn mir jemand der Erfahrung mit dem Thema hat, ein paar Kommentarzeilen zu dem Eintrag da lassen würde!

<a href="http://innoq.com/blog/wvk/transaction_request.html" onclick="window.open('http://innoq.com/blog/wvk/transaction_request.html','popup','width=920,height=930,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false"><img src="http://innoq.com/blog/wvk/transaction_request-thumb.png" alt="Ablauf einer Transaktion" /></a>

Das zweite Diagramm soll dem unbedarften Leser einen ungefähren Überblick über den Ablauf der Request-Verarbeitung verschaffen. In Wahrheit passieren noch ein paar unwesentliche Schritte mehr, aber ich denke nicht, dass das Weglassen dieser Schritte einen falschen Eindruck vermitteln könnte:

<a href="http://innoq.com/blog/wvk/request_handling.html" onclick="window.open('http://innoq.com/blog/wvk/request_handling.html','popup','width=760,height=740,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false"><img src="http://innoq.com/blog/wvk/request_handling-thumb.png" alt="Ablauf eines Requests" /></a>

Fragen? Ideen? => dafür gibt's das Kommentat-Formular unten ;-)]]></description>
         <link>http://innoq.com/blog/wvk/2008/02/ein_paar_diagramm.html</link>
         <guid>http://innoq.com/blog/wvk/2008/02/ein_paar_diagramm.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">Modellierung</category>
        
        
         <pubDate>Sun, 03 Feb 2008 19:28:09 +0100</pubDate>
      </item>
            <item>
         <title>Ideen für die Konfigurationsverwaltung</title>
         <description><![CDATA[Nach einem äußerst interessanten Vortrag in Essen über Themen aus der Quantenmechanik von Prof. Dr. Anton Zeilinger persönlich ergab es sich vorhin, dass Philipp und ich und ich zu einer kleinen Diskussionsrunde zusammenfanden, um ein Wenig über das Thema Konfigurationsverwaltung auf Webservern zu diskutieren. Dabei kam es, wie in solchen Diskussionen "leider" üblich, zu jeder Menge neuer Ideen, die ich am liebsten schon von Anfang an in meine Diplomarbeit eingebaut hätte.

Nachdem ich nun in meiner Serververwaltungs-Applikation so etwas wie Konfigurationsversionen eingebaut habe, stellte sich eine weitere, alles andere als triviale Frage: Wie ist das mit Konfigurations*dateien*? Bekanntlich habe ich es zur Prämisse gemacht, dass Konfigurationsdateien, sofern sie sich nicht durch Datenbankeinträge ersetzen lassen, direkt von Consolvix bearbeitet werden und nicht jedes Mal aus Datenbankeinträgen generiert werden (uns somit händische Änderungen womöglich rückgängig machen). Um hier auch verschiedene Konfigurationen mit verschiedenen Einstellungen zu erlauben, wäre es denkbar, jeder Konfigurationsdatei z.B. eine entsprechende Endung zu geben die mit dem Schlüssel der jeweils aktiven Konfiguration in der Datenbank übereinstimmt. Diesen Gedanken habe ich nicht weiter verfolgt, da er mir etwas umständlich erschien. Wesentlich besser finde ich die Idee, generell alle Konfigurationsdateien (z.B. das komplette /etc-Verzeichnis) mit Subversion zu 
verwalten. So könnte man Konfigurationen ändern wie man lustig ist, und wenn mal irgendwann das halbe System dadurch abgeschossen sein sollte, dann checkt man eben eine ältere Konfiguration aus und versucht es von neuem. Um dann noch aus verschiedenen Systemkonfigurationen (Produktion, Wartung, ...) wählen zu können, könnte man immer noch mit Branching arbeiten: Für jede mögliche Konfiguration wird einfach ein neuer Zweig des Repositorys angelegt. Nachdem ich dann mal kurz Gebrauch vom allwissenden Dämon Google gemacht hatte, stieß ich auf ein e Beschreibung, wie man mittels <a href="http://www.pjhyett.com/posts/159-installing-ruby-svn-bindings">SWIG die Subversion-Bindings für Ruby</a> installiert (für Debian-Benutzer ist es noch einfacher: apt-get install libsvn-ruby ;-)). Besser noch: nach weiterem Googlen fand ich dann <a href="http://rubyforge.org/projects/actsassvn/">das Rails-Plugin `acts_as_subversioned`</a> für versioniertes ActiveRecord, das Datenbankentitäten versioniert abspeichert! Etwas derartiges wäre eigentlich für mein Gesamtsystem von Anfang an sehr praktisch gewesen -- ich fürchte aber, dass es etwas zu viel Zeit kosten würde, das jetzt noch einzubauen (nach Ende der Diplomarbeit werde ich es aber auf jeden Fall weiter verfolgen!)

Ein weiteres Thema des o.g. Brainstormings war: Wie lasse ich Consolvix Veränderungen am System vornehmen, wenn diese nicht über die Datenbank abgefackelt werden? Momentan habe ich den Benutzer www-data einfach in die Gruppen gepackt, die Zugriff auf die zu den Diensten gehörenden Ordner hat, die es konfigurieren soll (Beispielsweise Gruppe subversion für /var/svn) Auf lange Sicht müsste dazu Consolvix aber root-Reche bekommen -- und spätestens hier sollten sämtliche Alarmglocken losklingeln. Also werde ich vermutlich folgende Lösung verwenden: Für alle durchzuführenden Änderungen im System wird ein Shell-Kommando oder -Script erstellt. Dieses wird an einen kleinen Dämon mit setuid=root weitergereicht, der genau zwei Kommandos ausführt: `sudo <Benutzer>` und das angegebene Kommando/Script. `<Benutzer>` ist hierbei immer die UID des gerade in Consolvix eingeloggten Benutzers. So wird sichergestellt, dass Consolvix selbst immer ein unprivilegierter Dienst bleibt und alle durchzuführenden Kommandos immer als der User ausgeführt werden, der gerade in Consolvix eingeloggt ist. Das geht, weil System- und Consolvix-Benutzer identisch sind.

<img alt="secure_consolvix_exec0.png" src="http://innoq.com/blog/wvk/secure_consolvix_exec0.png" width="380" height="260" />

Eine Idee war es, die so generierten Kommandos zuerst in ein Subversion-Repository einzuchecken, damit diese vom o.g. Dämon zuerst ausgecheckt und dann durchgeführt werden. Der Hintergedanke dazu war der, dass das erste Zielsystem für Consolvix aus einem Test- und einem Produktionssystem bestehen wird. Im Testsystem werden iterativ Änderungen vorgenommen und erst wenn das System zufriedenstellend lauft, werden diese auch am Produktionssystem vorgenommen. Hier wäre die Idee mit Subversion nicht schlecht, denn so würde sichergestellt werden, dass, ähnlich wie bei Rails-Migrations, immer alle Änderungen in der richtigen Reihenfolge und genau  so durchgeführt werden. 

<img alt="secure_consolvix_exec1.png" src="http://innoq.com/blog/wvk/secure_consolvix_exec1.png" width="630" height="240" />

Allerdings verletzt das die andere Arbeitsprämisse, nämlich dass manuelle Änderungen im System genauso behandelt werden sollen wie von Consolvix durchgeführte -- und jedes Mal  manuell ein Shell-Skript zu erstellen, dieses einzuchecken und dann ausführen zu lassen ist gelinde gesagt etwas umständlich. Im Mainframe-Bereich ist das zwar Praxis, aber wir betreiben ja nur einen kleinen Linux-Server... Ich denke, dass in die Richtung noch mehr Gedanken folgen werden, aber bis auf Weiteres werde ich erstmal so weitermachen wie bisher.]]></description>
         <link>http://innoq.com/blog/wvk/2008/01/ideen_fur_konfigurationsverwal_1.html</link>
         <guid>http://innoq.com/blog/wvk/2008/01/ideen_fur_konfigurationsverwal_1.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">Modellierung</category>
        
        
         <pubDate>Wed, 30 Jan 2008 22:13:35 +0100</pubDate>
      </item>
            <item>
         <title>Ein paar Worte zu Modulen in Ruby</title>
         <description>Als Ergänzung zu meinem letzten Eintrag zum Thema &quot;Rubys Objektmodell&quot; folgen ein paar Notizen dazu, wie sich Module in das Gefüge einfügen (müssen sie ja irgendwie, sonst wäre es kein Gefüge ;-))

- Wird ein Modul mittels `include` eingebunden, werden alle Modulmethoden zu *Instanzmethoden* der einbindenden Klasse.
- Wird ein Modul mittels `extend` eingebunden, werden alle Modulmethoden zu *Klassenmethoden* der einbindenden Klasse.
- es ist (in Rails) durchaus üblich, ein Modul `Foo` zu definieren, welches dann mit `include Foo` eingebunden wird, sowie ein Untermodul `Foo::ClassMethods`, welches mittels `extend Foo::ClassMethods` eingebunden wird. Diese Praxis habe ich einfach mal so übernommen.

So viel zu den Methoden. Doch was ist mit den Variablen? Wie wir alle wissen, werden *Klassen*variablen weitervererbt, *Instanz*variablen jedoch nicht (irgendwie logisch...). Aber bei Modulen...?
- Da ein Modul nicht instanziiert werden kann, kann es auch keine Instanzvariablen (`@foo`) haben -- ganz einfach. Wird ein Modul mittels `include` eingebunden, müssen alle `@foo`&apos;s also Instanzvariablen der Objekte werden; wird es mit `extend` eingebunden, sind es eben Instanzvariablen der Klasse (und NICHT etwa Klassenvariablen oder so...)
- Klassenvariablen (`@@bar`) werden bei `include` einfach übernommen -- sprich, was im Modul eine &quot;Klassen&quot;variable war, wird auch in (den Instanzen) der einbindenden Klasse als Klassenvariable erhalten bleiben. Bei `extend` jedoch sind alle im Modul definierten Klassenvariablen **nur** für die im Modul definierten Methoden erreichbar! Alle Versuche, aus dem Kontekt der Klasse (oder einer ihrer Instanzen) an sie heranzukommen, sind bei mir bislang gescheitert.

An einem Beispiel zeigt sich so was immer schön:

    module Foo
      @@truth = 42
    
      def say_the_truth
        p @@truth
      end
    end
    
    class Bar
      include Foo
    end
    Bar.new.say_the_truth # 42 *SMILE*
    
    class FooBar &lt; Bar
      def say_something
        p @@truth
      end
    end
    FooBar.new.say_something # 42 *SMILE*
    
    class Baz
      extend Foo
    
      def say_something
        p @@truth
      end
    end
    Baz.say_the_truth # 42 *SMILE*
    Baz.new,say_something # PENG! WUMMS! &quot;NameError: uninitialized class variable @@truth in Baz&quot; ... *Autsch*

Alles klar?
</description>
         <link>http://innoq.com/blog/wvk/2008/01/ein_paar_worte_zu_modulen_in_r.html</link>
         <guid>http://innoq.com/blog/wvk/2008/01/ein_paar_worte_zu_modulen_in_r.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">Ruby, Rails und &apos;drum und &apos;dran</category>
        
        
         <pubDate>Sun, 27 Jan 2008 03:31:23 +0100</pubDate>
      </item>
            <item>
         <title>Rubys Objektmodell</title>
         <description><![CDATA[OK, was ich jetzt hier schreibe ist nichts neues und auch schon auf viel bessere Art und Weise von <a href="http://whytheluckystiff.net/articles/seeingMetaclassesClearly.html">Why the Lucky Stiff</a> beschrieben worden. Jedenfalls trieb mich ein Bug in Consolvix dazu, mich nochmals intensiver mit dem Thema Metaprogrammierung und dem Ruby-Objektmodell auseinanderzusetzen. Es folgen ein Paar Notizen.

- *Objekte* in Ruby können **nur Variablen** aufnehmen -- Ein Ruby-Objekt hat **keine Methoden**
- Objekte sind in erster Linie dies: *Objekte*. Erst in zweiter Linie sind sie Instanzen einer *Klasse*. Auch Klassen sind Objekte (ABER auf C-Quellcode-Ebene sind Object und Class zwei verschiedene Structs -- ich halte diese Information für wichtig, wenn man wirklich blicken will, warum diese Class-Objekt-Abhängigkeit keine unendliche Rekursion mit sich bringt)
- Objekt-/Instanz-Methoden befinden sich in der *Klasse*, von der sich das Objekt ableitet. Eine Klasse ist nicht ein statisches, abstraktes Dingda, sondern ein Singleton-Objekt. Ein Objekt, das (Klassen-)Variablen UND Methoden aufnehmen kann. Eine Klasse eben. (Und hier würde dann die Rekursion einsetzen ;-))
- *Klassen*methoden befinden sich -- nein, nicht in der Klasse, die ja ein Objekt ist, sondern in der Klasse, die meistens *Metaklasse* genannt wird. 
- Klassen vererben ihre Methoden ihren Unterklassen. Somit steht, wenn man eine Klasse um eine neue Methode bereichert, sofort sämtlichen Unterklassen und sämtlichen Instanzen der Klasse diese Methode zur Verfügung. Wenn man aber einem einzelnen *Objekt* an dieser Stelle eine andere Implementierung dieser Methode geben möchte, so kann man dem Objekt diese Methode über die Metaklasse dieses Objektes zur Verfügung stellen. Methoden werden *zuerst in der Metaklasse dann erst in der Klassenhierachie* gesucht.
- Das Konzept der *Vererbung* erweitert eine Klassenhierachie vertikal, während *Module* die Klassenhierachie *horizontal* erweitern -- man könne also sagen, dass das Konzept der Metaklassen die Hierachie in der *tiefe* erweitern -- aber das klingt gleich wieder so esotherisch...
- Metaklassen können, da diese wiederum Objekte sind, selbst auch wieder Metaklassen enthalten. Eine Veränderung der Metaklasse einer Metaklasse einer Klasse zieht jedoch keinerlei Konsequenzen für die Klasse nach sich. Außerdem ist es sehr unwahrscheinlich, dass von diesem Konzept jemals jemand Gebrauch machen wird (OK, ich werde meinen kranken Geist darauf ansetzen, in einer freien Minute etwas passendes zu finden ;-))

Folgendes ER-Diagramm hab ich nach meinem Verständnis des Sachverhaltes zusammengestellt. Wenn jemand darin einen grundlegenden Fehler entdeckt, bitte sofort melden!

<a href="http://innoq.com/blog/wvk/RubyObjectModel1.html" onclick="window.open('http://innoq.com/blog/wvk/RubyObjectModel1.html','popup','width=763,height=375,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false"><img src="http://innoq.com/blog/wvk/RubyObjectModel-thumb.png" width="400" height="196" alt="" /></a>

Dieses Klassendiagramm habe ich nach dem ASCII-Diagram aus einem (vermutlich bekannten) Post in der <a href="http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/138979">Ruby-Talk</a>-Mailingliste gebastelt. Es stellt die Abhängigkeit der Klassen und Objekte untereinander dar. Wie man sieht, erbt letztendlich alles von Object. Die Klassen mit eingeklammerten Namen sind die jeweiligen Meta-Klassen (bzw. Singleton-Klassen-Instanzen...).

 <img alt="RubyObjectModelInheritances.png" src="http://innoq.com/blog/wvk/RubyObjectModelInheritances.png" width="511" height="241" />

Ich finde, dass das Bild etwas klarer wird, wenn man die Vererbung durch eine gerichtete Beziehung der Objekte untereinander ersetzt. `super` zeigt somit immer auf das Objekt der Elternklasse während `self` auf das Objekt der Singleton-Klasse zeigt.

<img alt="RubyObjectModelReferences.png" src="http://innoq.com/blog/wvk/RubyObjectModelReferences.png" width="501" height="251" />

So hat man im Wesentlichen die Abbildung des Ruby-Objektmodells auf C-Ebene vor sich: Vererbung und "magische Meta-Dingsda" sind nichts weiter als Structs, von denen einige lediglich Variablen, andere auch Methoden referenzieren können... der ganze Zauber gelüftet, aber eine Menge mehr Klarheit geschaffen :)

Zu dem ganzen ist anzumerken, dass nicht zu jedem Objekt a priori eine Singletonklasse existiert -- das *würde* unendlich viel Speicher erfordern. Eine Singletonklasse wird nur dann erstellt, wenn sie explizit angefordert wird, und zwar über

    class Foo
      # ...
    end
    
    obj = Foo.new

    class << obj
      # hier sind wir im Kontext der Metaklasse von obj!
    end
    
    class << Foo
      # hier sind wir im Kontext der Metaklasse von Foo!
    end

    class Foo
      class << self
        class << self
          # im Kontext der Metaklasse der Metaklasse von Foo ;-)
        end
      end
    end

Alles klar? Nicht? Dann hilft nur lesen des o.g. Artikels von Why the Lucky Stiff oder sich einfach mit anderen Dingen beschäftigen...
]]></description>
         <link>http://innoq.com/blog/wvk/2008/01/rubys_objektmodell.html</link>
         <guid>http://innoq.com/blog/wvk/2008/01/rubys_objektmodell.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">Ruby, Rails und &apos;drum und &apos;dran</category>
        
        
         <pubDate>Fri, 25 Jan 2008 00:18:47 +0100</pubDate>
      </item>
            <item>
         <title>Ein weiterer Rails-Bug</title>
         <description>Vielleicht erinnert sich der eine oder andere aus der Schnittmenge der treuen Leser dieses Blogs und der regelmäßig bei unserer Diplomandenrunde in Dortmund Anwesenden noch daran, dass wir &quot;damals&quot;  erwähnt hatten, dass es manchmal, aber nicht immer, in Rails zu einer Exception kommt, wenn man z.B. sowas hier probiert:

    @client.user.system_groups.access_rights

obwohl alles ganz sicher korrekt mit `has_many` usw. definiert wurde. Ich werde hier nichts breittreten, was mich grob geschätzt die letzten 4 Stunden und viel mehr Nerven als diese Stunden Sekunden haben, gekostet hat, sondern es in einem einfachen Satz zusammenfassen:

**NIEMALS in Join-Tables einen Primärschlüssel namens &apos;id&apos; verwenden!!**

das Problem ist, dass bei einem Join wie diesem:

    User.find(17).system_groups

dieses SQL generiert wird:

    SELECT * FROM `system_groups` 
      INNER JOIN groups_users 
        ON system_groups.id = groups_users.group_id 
    WHERE (groups_users.user_id = 17 )

Na, wem fällt&apos;s auf? genau, da steht `SELECT * FROM ...`, und nicht, wie es sich gehört, `SELECT system_groups.* ...`. Damit tritt der Spaltenname `id` nämlich zweimal im Resultat auf (einmal von der Gruppentabelle und einmal von der Join-Table), wobei letzten Endes die ID von der Join-Table von Rails verarbeitet wird und dann als FALSCHE `system_group_id` eingesetzt wird.

Nach dem Entfernen der `id` Spalte aus `groups_users` lief alles wie erwartet.

Man mag mich bei Gelegenheit dafür steinigen, dass ich in Join-Tables eine künstliche ID-Spalte verwende, aber Rails&apos; Verhalten bezeichne ich in diesem Fall als schlichtweg falsch. I hereby declare it a bug.</description>
         <link>http://innoq.com/blog/wvk/2008/01/ein_weiterer_railsbug.html</link>
         <guid>http://innoq.com/blog/wvk/2008/01/ein_weiterer_railsbug.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">Ruby, Rails und &apos;drum und &apos;dran</category>
        
        
         <pubDate>Mon, 21 Jan 2008 04:00:00 +0100</pubDate>
      </item>
            <item>
         <title>Von etwas komplizierteren Beziehungen</title>
         <description>Wenn A viele B hat, und C viele B hat, kann C auch viele A haben, wenn C :through benutzt. Wenn A aber viele B und B viele C hat, außerdem C zu vielen B gehört, dann kann C nicht auch viele A haben, selbst wenn B :through benutzt.

Ich wollt&apos;s nur mal erwähnt haben, sollte jemand von euch das auch mal probieren wollen.

Wie Bahnhof? Gut, dann nochmal kurz:

:through geht nicht bei has_and_belongs_to_many-Assoziationen.

Mein Problem:

    class AccessRight
      # ...
    end

    class AccessRightGrant
      belongs_to :acces_right
      belongs_to :subject,
                 :polymorphic =&gt; true
    end

    class SystemGroup
      has_many :access_right_grants,
               :as =&gt; :subject
      has_many :access_rights,
               :through =&gt; :access_right_grants
      has_and_belongs_to_many :users
    end

    class User
      has_and_belongs_to_many :system_groups
      has_many :access_right_grants,
               :as =&gt; :subject
      has_many :user_access_rights,
               :class_name =&gt; &apos;AccessRight&apos;
               :through =&gt; :access_right_grants
      has_many :access_rights,
               :class_name =&gt; &apos;AccessRight&apos;,
               :through =&gt; system_groups
    end

... geht also NICHT. 

Was ich erreichen möchte, ist dies: `User` hat `AccessRights`, `SystemGroup` hat `AccessRights`, `User` hat alle `AccessRights`, die `SystemGroup` auch hat. `User.access_rights` soll also *alle* , nicht nur des `User`&apos;s `AccessRights` zurückliefern (in obigem Code sollten erstmal nur die `AccessRights` der Gruppen geladen werden, nicht alle). `AccessRightGrant` ist die Linking Table zwischen `AccessRight` und `User`/`SystemGroup`, wobei letztere über die polymorphische `subject`-Spalte gelinkt werden.

Dem mit o.g. Code generierten SQL nach zu urteilen, liegt das Problem bei der HABTM-Beziehung. Bestätigt hat das ein Tauchgang in den Rails-Source, der übrigens mit seinen *n* Metaprogrammier-Ebenen mehr als faszinierend und beeindruckend ist, wenn man sich mal etwas Zeit für ihn nimmt. Bei einer normalen `has_many`-Beziehung zwischen `User` und `SystemGroup`könnte es funktionieren, ausprobiert habe ich das jedoch nicht.

Aber es lässt sich für alles eine Lösung finden und bis ich hierfür eine elegante Lösung gefunden habe, werde ich einfach ganz skrupellos brute-force-Methoden wie &quot;lade alle Rechte und durchsuche das Array&quot; benutzen. Tja, Rails, das haste nun davon :-)</description>
         <link>http://innoq.com/blog/wvk/2008/01/von_etwas_komplizierteren_bezi.html</link>
         <guid>http://innoq.com/blog/wvk/2008/01/von_etwas_komplizierteren_bezi.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">Modellierung</category>
                  <category domain="http://www.sixapart.com/ns/types#category">Ruby, Rails und &apos;drum und &apos;dran</category>
        
        
         <pubDate>Sun, 20 Jan 2008 00:51:37 +0100</pubDate>
      </item>
            <item>
         <title>Verdeckte Transaktionen</title>
         <description><![CDATA[Wie schon vor einiger Zeit in <a href="http://innoq.com/blog/wvk/2007/12/transaktionen_die_zweite.html">diesem Eintrag</a> beschrieben, bietet Consolvix eine durchaus ausgeklügelte Möglichkeit, Transaktionen über mehrere Schritte zu implementieren. Gestern Nacht kamen mir kurz vorm Einschlafen  dazu noch zwei Ideen, die ich vielleicht noch umsetzen möchte (hier wäre mir die Meinung eines Experten sehr willkommen).

 1. Momentan speichere ich die Daten zu einer Transaktion als YAML serialisiert im data-Feld einer `ConsolvixTransaction` ab. Wird die Transaktion abgebrochen, werden alle temporären Daten also gelöscht und gut ist. Aber eigentlich, ja EIGENTLICH, ist das ja nicht ganz sauber -- wenn man doch ein `User`-Objekt hat, und sei es nur ein temporäres, dann gehört das ja eigentlich in die `users`-Tabelle und in der Transaktion sollte nur die ID und der Typ des Objektes gespeichert werden. Wenn dann die Transaktion gelöscht wird, sollten diese temporären Objekte ebenfalls gelöscht werden. An sich kein Problem, ich bin mir sogar sicher, dass sich das äußerst elegant über HABTM und polymorphische Aggregation lösen ließe. Aber: So lange die Transaktion nicht abgeschlossen ist, befinden sich also unter den "gültigen" Objekten auch "ungültige", also solche, die überhaupt noch nirgends in der restlichen Applikation auftauchen sollten! Also müsste dann doch irgendwie jedes temporäre Objekt als solches markiert werden -- und dann hört die Sache wieder auf, elegant zu sein -- ganz im Gegenteil gar. Dabei sei angemerkt, dass theoretisch jede Entität (aus 20, 30, vielleicht auch irgendwann mal über 50 möglichen) in einer Transaktion vorkommen kann. Also doch lieber bei der jetzigen Methode (also dump/serialisieren) bleiben? Wie werden solche vorläufigen Daten in Businessapplikationen "der Großen" gehandhabt? Hilfe...?
 2. "Points of no Return" einbauen. Bitte was? Gerade bei Webhosting-Angelegenheiten gibt es Aktionen, die die Bestätigung des Benutzers/Kunden erfordern. Beispiel: neue Bestellung, bestehend aus vier Schritten. Schritt 1: Kunde wählt z.B. "5GB mehr Speicher". Schritt 2: Kunde bestätigt Bestellung und erklärt sich mit irgendwelchen Bedingungen einverstanden. Dann wird eine E-Mail an die Buchhaltung geschickt, diese bestätigt Schritt 3, sprich "Kunde bekommt nun 5 GB Speicher mehr abgerechnet". Dann wird eine E-Mail an den Admin geschickt, dieser bestätigt Schritt 4, dass die 5 GB auch tatsächlich freigeschaltet werden. Diese Transaktion hätte zwei "Points of no return": Nachdem der Kunde Schritt 2 bestätigt hat, kann er nicht mehr zu Schritt 1 zurück, was mit der aktuellen Transaktionsverwaltung aber jederzeit möglich wäre. Der zweite PonR wäre, nachdem die Buchhaltung ihren Teil bestätigt hat -- danach kann auch nicht mehr zu Schritt 3 zurückgesprungen werden, sondern entweder der Admin bestätigt auch Schritt 4, oder er bricht die ganze Transaktion ab und alles bleibt beim alten. Ein anderes Beispiel wäre z.B. das Registrieren eines neuen Accounts: der potentielle Kunde füllt drei Seiten Formularkram aus, schickt diese ab und kann danach nichts mehr an Schritt 1..3 ändern, auch wenn die Transaktion an sich erst abgeschlossen ist, wenn die Buchhaltung und der Admin (kann meinetwegen die gleiche Person sein) noch ihre 1...n Schritte abgeschlossen haben. Mir scheint es eigentlich sinnvoll und durchaus elegant, neben der Definition einer Sequenz von Actions als Schritte in einer Transaktion auch "Synchronisationspunkte" zu definieren, nach denen entweder abgebrochen oder weitergemacht, nicht aber zurückgesprungen werden kann. Wird das bei Datenbanktransaktionen nicht auch im Grunde genommen so verwendet? Stating the obvious? Denke ich nun wieder zu kompliziert? Meinungen? Buh-Rufe? Faule Eier?

Jedenfalls kommen noch weitere Änderungen an der bestehenden Transaktions-API hinzu, weil ich gemerkt habe, dass sich noch einige Komplifikationen ergeben, sobald verschiedene Teile einer Transaktion von unterschiedlichen Benutzern (teilweise noch nicht einmal vorhandenen!) ausgeführt werden können müssen.

...

und ich glaube, Deutsch ist tatsächlich die einzige Sprache, in der vier aufeinander folgende Verben ein grammatikalisch korrektes Konstrukt bilden können... ;-)]]></description>
         <link>http://innoq.com/blog/wvk/2008/01/verdeckte_transaktionen.html</link>
         <guid>http://innoq.com/blog/wvk/2008/01/verdeckte_transaktionen.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">Modellierung</category>
        
        
         <pubDate>Sat, 19 Jan 2008 23:58:54 +0100</pubDate>
      </item>
            <item>
         <title>Neues Aussehen</title>
         <description>Wie man sieht ist diese Nacht nicht ganz spurlos an diesem Blog vorbeigezogen. Ich hoffe das neue Layout gefällt dem einen oder anderen. Anregungen. Kritik und scharfe Munition  nehme ich gerne entgegen, dafür gibt&apos;s ja die praktische Kommentierfunktion.

Und: huch, wer hätte das gesacht,  auch ich kann kurze Posts schreiben! ;-)</description>
         <link>http://innoq.com/blog/wvk/2008/01/neues_aussehen.html</link>
         <guid>http://innoq.com/blog/wvk/2008/01/neues_aussehen.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">Philosophisches und anderer Schmalz</category>
        
        
         <pubDate>Wed, 16 Jan 2008 05:24:01 +0100</pubDate>
      </item>
            <item>
         <title>Etwas Modellierarbeit oder: es lebe die 42!</title>
         <description><![CDATA[Schon von Anfang an hadere ich mit mir, was die Modellierung der Benutzerklassen angeht (siehe anfängliche Posts...). Wie einigen aufmerksamen Lesern dieses Blogs bekannt sein dürfte, ist das Datenmodell nun so gestaltet, dass jede Entität, die ind er Wahren Welt auch ein auch ein Benutzer "ist", nun ein Benutzerobjekt aggregiert. Wenn ein Benutzer beispielsweise gleichzeitig einen E-Mail-, FTP- und Systemaccount hat, so sind das eben drei verschiedene Entitäten, die allesamt dasselbe Benutzerobjekt aggregieren. Dass es auch mit diesem Design zu Problemen kommen würde, war ja von Anfang an sonnenklar. Denoch werde ich diese Linie weiter verfolgen, zumal ja schon ein größerer Teil der Applikation darauf aufbaut. Doch nun gab's zwei kleine Änderungen:

- Entgegen aller Regeln der Redundanzvermeidung und Normalisierung wurde im `User` ein Fremdschlüssel auf den `Client `gelegt. So kommt man vom Benutzer aus wenigstens einfach an den "Besitzer", was ansonsten mit ganzen drei Joins bewerkstelligt werden musste.
- `FtpAccountsController`, `EmailAccountsController` und `SystemAccountController` sind nun allesamt `Kindsklassen` von UsersController. Alles was man mit einem User machen kann, kann man logischerweise auch mit den anderen User-Arten machen -- darum dieser Schritt.

<a href="http://innoq.com/blog/wvk/usermodel-classes.html" onclick="window.open('http://innoq.com/blog/wvk/usermodel-classes.html','popup','width=881,height=876,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false"><img src="http://innoq.com/blog/wvk/usermodel-classes-thumb.png" width="300" height="298" alt="" /></a>

Die Klassenhierachie für die Benutzertypen schaut also nun so aus:

<img alt="user-controllers-diagram.png" src="http://innoq.com/blog/wvk/user-controllers-diagram.png" width="320" height="350" />

Wer sich über den Einschub von `Consolvix::Application` wundert, dessen Verwunderung sei hoffentlich mit der Erklärung besänftigt, dass ich das nicht etwa gemacht habe um die Fläche im Klassendiagramm etwas weiter aufzufüllen, sondern einfach um im `ApplicationController` etwas Übersicht zu schaffen. Alle privaten und internen Funktionen stehen nun weitestgehend in `Consolvix::Application`, während im (Application)Controller im Wesentlichen nur noch Actions stehen, die der Besucher direkt aufrufen kann.

Und was um alles in der Welt hat das alles mit der 42 zu tun? Nun, Dies ist der 42. Eintrag. In dem Sinne Lang lebe das Universum! ;-)]]></description>
         <link>http://innoq.com/blog/wvk/2008/01/ein_modellierarbeit_oder_es_le.html</link>
         <guid>http://innoq.com/blog/wvk/2008/01/ein_modellierarbeit_oder_es_le.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">Modellierung</category>
        
        
         <pubDate>Tue, 15 Jan 2008 20:31:18 +0100</pubDate>
      </item>
            <item>
         <title>INI-Files</title>
         <description><![CDATA[Heute Nacht saß irgendwann wie betäubt vor meinem Quelltext und machte ein apathisches Auditing, bis ich auf die Stelle stieß, wo ich im TracEnviironment-Model die Trac.ini verarbeite. Wie bereits anderswo beschrieben, werden die Werte aus der ini-Datei als Attribute der jeweiligen TracEnvironmant-Instanz abgelegt, damit ich darauf zugreifan kann wie auf ein ActiveRecord-Objekt. Das übernimmt diese Methode:

    def parse_config_file!(file=nil)
      config  = {}
      section = ''
      begin
        file = File.new(file||self.config_file)
        file.each_line do |line|
          if /^\[([a-z0-9_]*)\]$/.match line
            section = $1
          elsif /^\s*([a-zA-Z0-9_]*)\s*=\s*(.*)$/.match line
            self.send "#{section}__#{$1}=", $2
          end
        end
      rescue Errno::ENOENT
      end
      config
    end

Zurückschreiben geht ähnlich, halt einfach den gleichen Weg rückwärts. Das funktioniert alles Prima so weit udn ich denke auch nicht, dass ich das so bald ändern werde. Dennoch packte mich die Neugier, ob es nicht vielleicht ein Rails-Plugin oder ein Gem zurm INI-Dateihandling gibt. Und siehe da: das inifile-Gem tut genau das: <a href="https://rubyforge.org/projects/inifile/"> https://rubyforge.org/projects/inifile</a>. Intern werden die "Sections" als Hash gespeichert und auf die Sections wird ebenfalls wie ein Hash zugegriffen. 

Alles sehr nett. Viel Spaß damit, sollte jemand das mal brauchen...]]></description>
         <link>http://innoq.com/blog/wvk/2008/01/inifiles.html</link>
         <guid>http://innoq.com/blog/wvk/2008/01/inifiles.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">Ruby, Rails und &apos;drum und &apos;dran</category>
        
        
         <pubDate>Tue, 15 Jan 2008 19:10:33 +0100</pubDate>
      </item>
            <item>
         <title>Neues System, neue Probleme</title>
         <description>Mal wieder ging ein potentiell produktiver Tag ohne ein produktives Ergebnis zu Ende, weil mein Apache nicht mit den Rails-Anwendungen spielen wollte. `mod_cgi` meldete das übliche &quot;premature end of script headers&quot;, was im Wesentlichen nichts weiter aussagt als &quot;irgentwas stimmt da nicht&quot;. `mod_fcgid` hatte anschienend noch viel weniger Lust, denn eine Instanz nach dem Anderen hängte sich einfach nach einem &quot;unexpected Signal 11&quot; auf, später gab&apos;s dann auch noch lustige Segfaults dazu. Neuinstallieren von Apache und Modulen und trallala brachte alles nichts, auch die Schreib-, Lese- und Ausführrechte waren alle korrekt gesetzt *FRUST*.

Schließlich und endlich rang ich mich dann dazu durch, den Apachen mitsamt des Fcgid-Moduls selber zu kompilieren, denn vielleicht gab es ja tatsächlich Probleme, weil der eine oder andere Teil noch im 32 Bit-Modus lief. Glücklicherweise ist selber bauen und dann installieren unter Debian sehr sauber und einfach:

    $ cd /usr/src
    $ apt-get source apache2 libapache2-mod-fcgid
      ... [ratter] ...

das holt erstmal die ganzen Sourcen. Anschließend wird kompiliert:

    $ cd apache2-2.2.6
    $ fakeroot debian/rules binary
      ... [ratter ... ratter ... ratter] ...

dito für mod_fcgid. Im Verzeichnis /usr/src liegen anschließend einige `.deb`s:

    apache2_2.2.6-3_all.deb
    apache2.2-common_2.2.6-3_amd64.deb
    apache2-dbg_2.2.6-3_amd64.deb
    apache2-doc_2.2.6-3_all.deb
    apache2-mpm-event_2.2.6-3_amd64.deb
    apache2-mpm-perchild_2.2.6-3_all.deb
    apache2-mpm-prefork_2.2.6-3_amd64.deb
    apache2-mpm-worker_2.2.6-3_amd64.deb
    apache2-prefork-dev_2.2.6-3_amd64.deb
    apache2-src_2.2.6-3_all.deb
    apache2-threaded-dev_2.2.6-3_amd64.deb
    apache2-utils_2.2.6-3_amd64.deb

Installiert werden sollten jedoch nicht alle (genauer gesagt geht das gar nicht). Es reicht, common, mpm-worker, utils und fcgid zu installieren.

    # dpkg -i apache2.2-common_2.2.6-3_amd64.deb \
       apache2-mpm-prefork_2.2.6-3_amd64.deb \
       apache2-utils_2.2.6-3_amd64.deb

wenige Minuten später ... siehe da ... der Apache startet (OK, das hätte ich auch erwartet) und Rails rennt wieder. Geschafft!

Vielleicht noch ein paar Worte zu den verschiedenen MPM-Paketen oben: Seit der Version 2.X besteht der Apache aus zwei Teilen, einmal einem `common`-Paket und einem `mpm-*`-Paket. Die eigentliche Arbeit, nämlich das Bedienen der Clients, macht je ein &quot;Arbeiter&quot;. Da der Apache bekanntlich durchaus 1000+ Anfragen pro Sekunde verarbeiten können muss, versteht sich von selbst, dass da irgendwie parallele Prozesse am Werk sein müssen. Und tatsächlich, &quot;MPM&quot; steht für *Multi-Processing Module*.

MPM-PREFORK ist das klassische Apache-Worker-Modell, wo sich einfach beim Start des Servers schon mehrere Apache-Instanzen im Speicher einnisten. Jede Instanz für sich genommen arbeitet singlethreaded. Dieses &quot;Thread&quot;-Modell ist sehr ausgereift und meines Wissens neben MPM-ITK das einzige, was mit Rails (und auch PHP5) zusammenarbeitet.

MPM-ITK erlaubt es, eine eigene UID und GID pro VirtualHost anzulegen, also ähnlich wie `mod_suexec` es für PHP tut. Das Klingt auf jeden Fall für meinen Server schonmal sehr interessant...

Die anderen MPM-Modelle sind entweder nicht sonderlich ausgereift oder sonstwie ungeeignet, deswegen werde ich nicht weiter drauf eingehen und mich einfach freuen, dass der alte Indianer wieder läuft :-)
</description>
         <link>http://innoq.com/blog/wvk/2008/01/neues_system_neue_probleme.html</link>
         <guid>http://innoq.com/blog/wvk/2008/01/neues_system_neue_probleme.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">Ruby, Rails und &apos;drum und &apos;dran</category>
        
        
         <pubDate>Tue, 15 Jan 2008 03:41:24 +0100</pubDate>
      </item>
            <item>
         <title>Neue Hardware braucht der Mensch</title>
         <description>Neues Jahr, neuer Rechner, so dachte ich mir. Endlich war es dann letzte Woche auch so weit, dass hier ein Paket nach dem anderen eintrudelte und sich im Laufe eines Nachmittags ein neuer Rechner zusammenfügte. Nach vielen Jahren erfüllte sich endlich mal wieder ein kleiner Traum, nämlich die von schneller Hardware und t&lt;\epsilon Reaktionszeit für flüssiges Arbeiten. Man mag staunen, aber ein AMD Athlon mit 1200MHz und 1GB Speicher ist nicht mehr ausreichend, um mit KDE flott Webentwicklung betreiben zu können. Nun steht hier also ein schöner Core2Quad mit 6GB Speicher und der rennt mir sozusagen davon -- sogar mit transparenten Fenstern und Schatten und allem trallala :-). Der Bootvorgang dauert keine Minute und 4-6 Sekunden nach dem Login ist KDE vollständig geladen. WOW!

Aber es hat leider mehr als drei Tage gedauert, bis dieses System mal vernünftig lief (und einen Tag bis sich überhaupt erstmal ein Installationssystem booten ließ). Ich sage nur: 64Bit sind so viel Fluch wie Segen. Von allen Live-CDs die Philipp und ich durchprobiert haben (Debian, Knoppix, Ububntu, SuSE, Sidux) wollten gerade mal zwei starten und bei keinem funktionierten die Onboard-LAN-Ports -- Stichwort nVidia nForce. Das forcedeth-Modul was zum Betrieb der Ethernetports nötig ist, wurde zwar unter Sidux geladen, auch ließen sich beide Ports einrichten und ansteuern, aber tatsächlich wurde nichts über die Leitung geschickt. Ein Glück dass hier noch eine alte 3Com-Karte herumschwirrte, mit der bin ich jetzt online.
Schließlich gelang es, über Philipps Mac eine 64-bit Debian-Netinst-CD zu laden (Hier der Hinweis an potentielle Nachahmer: ia64 ist NICHT, wie es der Name nahe legt und ich es erst vermutete, die Archikektur eines Intel Core2Duo/Quad -- es SOLLTE i386 gehen (ging dann auch, nachdem im BIOS gerumgedreht wurde, ganz komisch alles *g*), richtig ist aber amd64, auch wenn&apos;s ein Intel-Prozi ist. Damit lief jedenfalls der Rechner ziemlich bald und mit einem selbst kompilierten Kernel (t_compile &lt; 30 min) ohne die ganzen optionalen Komponenten rennt er gar.

Irgendwie muss man aber die überschüssige Rechenleistung auch wieder los werden, und somit erachte ich es als selbstverständlich, die als RAID1 geschalteten Platten zu verschlüsseln. der neue Debian Sid-Installer macht es gar möglich, schon bei der Installation ein Software-RAID und Verschlüsselung mit allem drum und dran einzurichten. Das Problem ist nur: es funktioniert nicht so wie man erwartet. Der Installer ermöglichte es mir problemlos, /dev/sda1 und /dev/sdb1 zu einem RAID1-Verbund zusammenzufassen, das entstandene /dev/md0 zu verschlüsseln und darauf wiederum zwei Partitionen (/ und swap) anzulegen. Das System ließ sich absolut einwandfrei installieren. Nur leider konnte das System danach nicht booten, da der Device-Mapper, der für das mounten verschlüsselter Partitionen zuständig ist, noch nicht geladen sein kann, bevor der Kernel das RAID zusammengefügt hat, und das RAID nicht zusammengefügt werden kann, bevor / gemountet ist -- jedenfalls ist das ein bekannter und gemeldeter Bug und ich vermute stark, dass das nächste Release von Debian diese Möglichkeit nicht mehr im Installer eingebaut haben wird.
Jedenfalls liegt / jetzt weiterhin unverschlüsselt auf der Platte, aber die restlichen Dateisysteme sind allesamt mittels dm-crypt verschlüsselt. Ich kann nicht behaupten, dass dadurch wie Performanz des System in irgendwelcher Weise beeinträchtigt wird.

So, doch nun: auf ins (endlich wieder) produktive Arbeiten! Nebenbei kann ja mal KDE 4 compilen, bin gespannt wie lange das dauert (Qt alleine brauchte 15 min mit 10 Threads)...</description>
         <link>http://innoq.com/blog/wvk/2008/01/neue_hardware_braucht_der_mens_1.html</link>
         <guid>http://innoq.com/blog/wvk/2008/01/neue_hardware_braucht_der_mens_1.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">Philosophisches und anderer Schmalz</category>
        
        
         <pubDate>Mon, 14 Jan 2008 02:44:17 +0100</pubDate>
      </item>
      
   </channel>
</rss>
