Archive for März, 2008

AltGr-Taste im IRB von InstantRails aktivieren

Samstag, März 22nd, 2008

InstantRails ist eine einfache Möglichkeit, unter Windows Rails-Anwendungen zu Entwickeln. Ruby, Rails, Apache und MySQL sind in diesem Paket gebundelt und müssen nicht installiert werden. Das Paket kann einfach entpackt werden und man kann loslegen (der Pfad darf allerdings keine Leerzeichen enthalten).

Die Freude wärt aber nur kurz, wenn man irb bzw. die Rails-Konsole über script/console benutzen möchte.

Dort funktionert nämlich die AltGr-Taste nicht, d.h. man kann kein @, [, ], oder | eingeben. Ich hatte dieses Problem bereits früher (konnte es beheben und vergaß es) und bekam es jetzt wieder beim Umstieg auf InstantRails 2 (mit Rails 2.0.2).

Lösung:

Man muss eine .inputrc-Datei erzeugen, die AltGr-Tastenkombinationen beschreibt. Diese Datei ist bei InstantRails schon enthalten. Sie enthält folgendes

"\M-[": "["
"\M-]": "]"
"\M-{": "{"
"\M-}": "}"
"\M-\\": "\\"
"\M-|": "|"
"\M-@": "@"
"\M-~": "~"
"\M-$": "$"

Und befindet sich im Verzeichnis <InstantRails>\ruby\bin\inputrc.euro

In der Datei irb.bat im gleichen Verzeichnis muss hinter dem @ECHO OFF folgende Zeile hinzugefügt werden:

SET INPUTRC=<pfad-zur-inputrc>\.inputrc

Es gibt noch andere Lösungsvorschläge, die aber zumindest für InstantRails nicht funktionieren. Die .inputrc gehört am besten ins Homedirectory des aktuellen Benutzers, also nach c:\Dokumente und Einstellungen\<Benutzername>. Wichtig sind in diesem Fall Anführungszeichen um die Pfadangabe, da sie Leerzeichen enthält!

Falls es eine Möglichkeit gibt die inputrc.euro aus dem bin-Verzeichnis direkt (ohne Angabe des Pfades) einzubinden, lasst es mich wissen. Ich habe bei kurzem überfliegen der Umgebungsvariablen aber nichts passendes gefunden, beispielsweise eine Variable mit dem aktuellen Pfad zum InstantRails-Verzeichnis.

(Ergänzung: Selbstverständlich muss man die .inputrc nicht woanders hin kopieren sondern kann Sie direkt mit absoluter Pfadangabe aus dem bin-Verzeichnis einbinden. Da man das InstantRails-Verzeichnis aber umbenennen und umkopieren kann, und InstantRails trotzdem funktioniert, ist eine absolute Pfadangabe zu “gefährlich”)

Richtige Verwendung von GET- und POST-Requests (Oder: Selbsthack mit Alexa)

Freitag, März 21st, 2008

Das Projekt Spekunauten befindet sich zur Zeit in der Testphase. Auf der Plattform ist noch nicht viel Publikumsverkehr, da noch keine Marketingmaßnahmen stattgefunden haben. Es gibt trotzdem schon Mitglieder und Beiträge dort, die größtenteils von uns selbst verfasst wurden. Vor ein paar Tagen stellt ich plötzlich fest, dass alle Beiträge nach dem 1.2.2008 gelöscht worden waren.

Ich dachte zuerst, dass einer der anderen Projektteilnehmer das getan hätte, um dort zum Start hin etwas aufzuräumen (die selbst erstellten Beiträge haben nicht so hohe Qualität). Niemand wollte es gewesen sein. Ich vermutete anschließend einen schwierig aufzuspürenden Fehler (die Anwendung wurde per Unit-Test ausreichend abgeklopft, wo sollte sich der Fehler verstecken?), aber ein Blick in die Logfiles zeigte, dass die Beiträge tatsächlich über das Admin-Menü gelöscht wurden- und zwar vom Alexa-Crawler!

Wie konnte das sein? In einem Controller im Admin-Bereich hatte ich ein

before_filter :require_admin

vergessen, so dass man diese Seite auch ohne Admin-Login aufrufen konnte. So weit so gut, nur woher kannte Alexa die URL? Ich benutze das SearchStatus-Plugin für den Firefox-Browser, welches den Google-Page- und Alexa-Rank der aktuellen Seite anzeigt. Darüber muss der Admin-Link zu Alexa.com gelangt sein und wurde anschließend vom Alexa-Crawler besucht. Auf der besuchten Seite gab es eine Liste mit allen Beiträgen der Spekunauten-Seite, der auch die Links zum Löschen enthielt. Diese hat der Crawler besucht und dadurch die Beiträge gelöscht.

Hinter diesem Vorfall steckt mehr als die Lektion, beim Absichern der Controller besser aufzupassen. Die Lösch-Aktion wurde durch einen normalen Link, also einen GET-Request ausgelöst. Das W3C hat zur Verwendung von POST vs. GET-Requests schon angemerkt, dass GET-Requests nur für “ungefährliche” Aktionen benutzt werden sollten (POST bedeutet “The interaction changes the state of the resource”).

Diese Empfehlung wird sogar im Railsbuch erwähnt: GET-Requests dürfen nur für Aktionen verwendet werden, die ohne Schaden mehrmals durchgeführt werden können. Schließlich steht nach dem Request diese URL in der Browserzeile und könnte durch einen Reload (versehentlich) nochmals aufgerufen werden- im Falle eines POST-Requests erscheint bei den meisten Browsern aber eine Warnung. Crawler füllen keine Formulare aus, daher hätte der Alexa-Bot in meinem Fall auch keine Löschaktion durchgeführt.

Probleme mit restful_authentication

Donnerstag, März 13th, 2008

Das Plugin restful_authentication ist der Nachfolger des bekannten acts_as_authenticated Login-Generators. Im Rails-Wiki wird dieses Plugin als “the only sane solution” beworben, falls man einen Login-Generator sucht.

Was genau macht das Plugin? Es erzeugt Login und Registrierungsformulare, ein User-Model, die Möglichkeit die Email-Adressen aus dem Registrierungsformular per Email zu verifizieren (durch einen per Email verschickten Aktivierungs-Link) und vieles mehr. Ich kann es nur wärmstens Empfehlen, insbesondere als Alternative zur eingeschränkteren Login-Funktionalität wie sie im “Agile Webdevelopment with Rails”-Buch vorgestellt wird!

Naja, bei der erstmaligen Benutzung von restful_authentication hatte ich jedoch ein Problem, dessen Lösung ein wenig mehr Suchaufwand erfordert hat, deswegen möchte ich sie hier vorstellen.

Restful_authentication benötigt zwei Controller, per Default “users” (zum Erzeugen neuer Benutzerkonten und zur Emailverifikation) und “sessions” (zum Erzeugen einer neuen Login-Session). Die Namen für die Controller kann man allerdings selbst festlegen. Ich habe statt sessions lieber session gewählt, was mir sinnvoller erschien (session/create vs. sessions/create, es wird ja schließlich nur eine Login-Session erzeugt). Letztendlich spielt der Name aber natürlich keine Rolle, da man ja named Routes benutzen kann.

Beim Login-Versuch bekam ich immer folgende Fehlermeldung:

uninitialized constant SessionsController

Die Lösung fand ich unter http://beast.caboo.se/forums/2/topics/1077:
In routes.rb muss die Zeile

map.resource :session

durch

map.resource :session, :controller => "session"

ersetzt werden, da sonst der Controllername automatisch (falsch) per Pluralization erzeugt wird.