cloudControl für Ruby-Entwickler

Ich muss zugeben, dass ich dem aktuellen Hype um das Thema Cloud Computing ein wenig skeptisch gegenüber stehe. Es scheint mir so, dass es sich dabei zwar durchaus um eine interessante Lösung handelt, die jedoch mal wieder in einer medialen Welle viel zu hoch gepriesen wird.

Für Webentwickler kann Cloud Computing jedoch ein paar interessante Vorteile bieten, die nicht von der Hand zu weisen sind. Vor allem die Idee, sich keine Gedanken mehr um die Serverkapazität und die Bereitstellung der Plattform einer Anwendung machen zu müssen, erscheint mir sehr attraktiv. Oft genug erlebt man es, dass Webseiten, die beispielsweise in einem Nachrichtenmagazin erwähnt werden, kurz nach dessen Veröffentlichung nicht mehr erreichbar sind, da die Server nicht dem Besucheransturm gewachsen waren. Solche ärgerlichen Ausfälle, bei dem wertvolle Benutzer verloren gehen, könnten in der „Cloud“ erfolgreich verhindert werden (Vorausgesetzt die Cloud ist entsprechend leistungsstark ;) ).

Der deutsche Anbieter cloudControl, der sich derzeit auf seinen Start vorbereitet, verspricht darüber hinaus noch einige Vorteile für die Entwickler selbst. Dazu zählen z.B. geringer Administrationsaufwand und Funktionen für die Teamarbeit. Neben den Sprachen PHP, Java und Python wird auch Ruby unterstützt, was für mich hochinteressant ist.
Ich bin sehr gespannt wie sich die Arbeit mit der Cloud letztendlich gestaltet und habe mich daher für die Beta-Phase registriert. Je nachdem wie sich das Thema für mich entwickelt, werde ich hier darüber berichten.

Share

ActionMailer E-Mail Versand testen

Ich habe soeben nach einer Möglichkeit gesucht, um den Versand einer E-Mail mittels ActionMailer in meinen Functional-Tests zu testen.
Beim Rails-Testing werden die E-Mails nicht real versandt, sondern nur in einer Queue gespeichert. Das ermöglicht es einfach den Inhalt der Queue abzufragen und somit den Versand der E-Mail sicher zu stellen.
Allerdings sollte auch bedacht werden, dass dadurch nur das reine Erstellen der E-Mail geprüft wird. Mögliche SMTP-Fehler beim Versand etc. bleiben dadurch unentdeckt!

  1. test "should send lost password mail" do
  2.  ActionMailer::Base.deliveries.clear
  3.  post(:lost_pwd, { :username => 'calvin', :email => 'calvin@krani.net' })
  4.  assert !ActionMailer::Base.deliveries.empty?    
  5. end

In diesem Beispiel soll geprüft werden, ob nach dem Aufruf der „Lost Password“ Action auch wirklich die E-Mail mit dem neuen Passwort generiert wird.
Hinweis: Es empfiehlt sich genauso wie in dem Beispiel, in jedem Test zunächst die Queue zu leeren, um sicher zu stellen, dass nicht schon E-Mails aus vorhergehenden Tests in der Queue stehen.

Share

Fehler „undefined method use_transactional_fixtures=“ nach Rails Update

Nach dem Update von Ruby on Rails auf die Version 2.3.5 habe ich beim Ausführen meiner Tests plötzlich diesen Fehler erhalten:

./test/test_helper.rb:22: undefined method `use_transactional_fixtures=' for Test::Unit::TestCase:Class (NoMethodError)

Mit Rails 2.3 hat sich der Name für die Klasse der Testhelper geändert. Um das Problem zu lösen, muss daher einfach in der Datei /test/test_helper.rb im jeweiligen Applikations-Verzeichnis der alte Klassenname

Test::Unit::TestCase.

durch

ActiveSupport::TestCase

ersetzt werden.

Share

ActiveRecord: Vorsicht bei der Massenänderung von Attributen

Rails bietet einfache Möglichkeiten um einem Objekt alle benötigten Attribute zuzuweisen. Einem ActiveRecord Model können z.B. schon bei der Instanziierung alle gewünschten Attribute aus den Request-Parametern (z.B. aus einem Formular) übergeben werden. Dieses Vorgehen nennt sich im Rails-Jargon „Mass-assignment“.

Nehmen wir an wir haben ein Model „Comment“, dass die Kommentare von Benutzern einer Webseite speichert. Um Spam vorzubeugen, sollen alle Kommentare erst nach redaktioneller Überprüfung angezeigt werden, weshalb das Model ein Attribut „reviewed“ besitzt. Nur wenn dieses den Wert „1“ hat, wird der Kommentar öffentlich angezeigt.
In der Methode für die Speicherung eines neuen Kommentars steht nun folgender Code:

  1. @comment = Comment.new(params[:comment])

Würde der Anwender den Request nun so manipulieren (z.B. durch das Einfügen eines weiteren Feldes im HTML-Formular), dass dem Host der Parameter params[:comment][:reviewed] mit dem Wert „1“ übergeben wird, wäre die redaktionelle Prüfung umgangen.

Um das zu verhindern, gibt es in ActiveRecord die Methode attr_accessible. Mit dieser kann eine Whitelist der Attribute erstellt werden, die durch Mass-assignment verändert werden dürfen. Die Methode attr_protected bietet die selbe Funktionalität, jedoch mit einem Blacklist-Verfahren, d.h. es werden Attribute definiert, die nicht verändert werden dürfen.

Im Beispiel der Kommentare, müsste man also im Model „Comment“ diesen Code hinterlegen:

  1. attr_protected(:reviewed)

Dann kann das Attribut nur noch mit dem direkten Zugriff manipuliert werden z.B:

  1. comment.reviewed = true

Ich persönlich bevorzuge übrigens das Whitelist-Verfahren, da somit Flüchtigkeitsfehler bei der Entwicklung vermieden werden können ;-)

Share

Praktische Einzeiler In Ruby

Hier ein kurzer Tipp um den Quellcode in Rails bzw. Ruby etwas übersichtlicher zu gestalten.

In dem man in Ruby einer Anweisung eine Bedingung mittels if oder unless nachstellt, kann bestimmt werden, ob die Anweisung ausgeführt wird oder nicht.

Das heißt derartiger Code

  1. if @category_id == '1'
  2.    @title = 'Home'
  3. end

wird ersetzt durch:

  1. @title = 'Home' if @category_id == '1'

Bei Verwendung von unless statt if wird die Negativität der Bedingung geprüft.

Weiterhin können mit dem Schlüsselwort and zwei Anweisungen miteinander verknüpft werden.  Ich nutze das besonders oft um die Weiterleitung und die Übergabe einer Flash-Nachricht miteinander zu verbinden:

  1. flash[:error] = 'Objekt nicht gefunden' and redirect_to(index_path)
Share

Javascript: Mausposition bestimmen

Das Ermitteln der Mausposition mittels Javascript hat sich für mich als nicht ganz einfach erwiesen.
Ich wollte die Mausposition auf einem Bild bestimmen. Leider müssen hier für unterschiedliche Browser wieder unterschiedliche Methoden angewendet werden.
Nach langem Suchen und Probieren habe ich endlich eine Funktion gebastelt, die ich im Firefox 3.5, Opera 10, Internet Explorer 8 und Internet Explorer 6 erfolgreich getestet habe.

  1. function mouse_pos(e, id){
  2.    ievar = typeof(document.all)=='object'?2:0;
  3.    x = e.clientX;
  4.    y = e.clientY;
  5.    i = document.getElementById(id);
  6.    xpos = x – i.offsetLeft – ievar;
  7.    ypos = y – i.offsetTop – ievar;
  8.    return [xpos, ypos];
  9. }

Als Übergabeparamter werden das Event und die ID des Bildes erwartet. Zurückgegeben wird ein Array in der Form [xpos, ypos].

Share

Umgebungsvariablen in Rails abrufen

Häufig möchte man für eine Webapplikation die IP-Adresse des Anwenders, dessen Browser o. ä. ermitteln. Auch werden einige Variablen die Server-Umgebung oder den HTTP-Request betreffen (z.B. URI, der augerufen wurde) immer wieder benötigt.

In PHP gibt es dafür das $_SERVER[] Array. In Rails werden diese Informationen vom request Objekt breitgestellt. Dieses Objekt stellt eine Menge von Methoden zur Verfügung über die sich die Werte abrufen lassen. Eine Dokumentation dieser Methoden findet sich hier.

Wer eine ähnliche Lösung wie in PHP bevorzugt, kanns ich dem env Hash, der ebenfalls vom request Objekt zur Verfügung gestellt wird, bedienen.

Um die IP-Adresse des Anwenders auszulesen, sieht das dann so aus:

  1. ip_adress = request.env['REMOTE_ADDR']

Weitere wichtige Varialben:

  1. #Server Name
  2. request.env['SERVER_NAME']
  3. #URI mit der die Seite aufgerufen wurde
  4. request.env['REQUEST_URI']
  5. #User-Agent (Browser) des Anwenders
  6. request.env['HTTP_USER_AGENT']
  7. #Art des Requests (GET/POST/PUT/DELETE)
  8. request.env['REQUEST_METHOD']
  9. #String aller Cookies
  10. request.env['HTTP_COOKIE']
  11. #Vom Anwender akzeptierte Charsets
  12. request.env['HTTP_ACCEPT_CHARSET']
Share

Erster Eintrag

Hiermit eröffne ich dieses Blog mit dem ersten obligatorischen Eintrag. :-)

Jeder, der gerne etwas über die Hintergründe dieses Blogs erfahren möchte, kann sich hier etwas belesen. ;-)

In diesem Sinne… bis zu meinem ersten richtigen Blog-Eintrag!

Share