Ruby on Rails Screencast - Implementation einer User Anmeldung

Für eine kommende Vorlesung über Test Driven Development habe ich einen Screencast angefertigt.

Das ganze natürlich in Rails mit Test::Unit und Vim (wegen der Sparsamkeit mit dem Screenplatz).

Das Auditorium kennt Rails größtenteils nicht, weshalb es ein einfach gewähltes Beispiel ist:
Die Implementierung eines simplen Authentifizierungsmechanismus, der einen Nutzer am System anmeldet.

Screencast Rails Session Authentication from Stefan Wienert on Vimeo.

Das genutzte Programm zur Aufnahme war Xvidcap. Sehr genial.

Mal wieder ein paar Links zum Thema Rails und Vim

Vim:

Rails:

Umstellung auf "www.stefanwienert.net" und Passenger mit apache mod userdir

Diejenigen, die meinen Feed abonniert haben, haben es wahrscheinlich schon gemerkt, da die ganzen Items als ungelesen markiert sein könnten.
Da ich passenger verwende, aber gleichzeitig noch apache mit mod_userdir nutzen möchte, blieb mir nichts anderes übrig als den Hauptteil der Site auf eine Subdomain zu legen. Aus irgendwelchen unerfindlichen Gründen hatte ich damals “site.stefanwienert.net” genommen. Jetzt ist mir mal aufgefallen, dass die Wahl der Subdomain “www.” deutlich klüger gewesen wäre.

Anfragen an mod_userdir können bei dieser Methode dann einfach durch “http://hauptdomain/~username” entgegengenommen werden. Die Haupt Rails Domain, auf die der Nutzer bei Erstkontakt stoßen sollte, ist dann “www.stefanwienert.net” und wird dank Passenger dann an einen Ruby-Prozess dispatcht. Dazu muss man einfach nur zwei vhosts in seiner “/etc/apache2/sites-enabled/…” aktivieren:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# Hier fuer die Hauptdomain, um weitere Websites zu ermoeglichen
# z.B. php Wikis oder Userspaces
<VirtualHost *:80>                                      
      ServerAdmin s59605@htw-dresden.de                 
      ServerName stefanwienert.net                      
      DocumentRoot /var/www                             
#   PassengerHighPerformance on                         
        <Directory /var/www/>                           
                Options Indexes FollowSymLinks MultiViews
                AllowOverride All                        
                Order allow,deny                         
                allow from all                                             
        </Directory>                                                           
</VirtualHost>    

# jetzt der eigentliche Rails Prozess
<VirtualHost *:80>                                                             
        ServerAdmin info@stefanwienert.net                                     
        ServerName www.stefanwienert.net                                       
        ServerAlias site.stefanwienert.net                                           
        #RailsBaseURI /site                                                    
        DocumentRoot /path/to/rails/public                         
# gzip html, css and js                                                       
        AddOutputFilterByType DEFLATE text/html text/css application/x-javascript application/javascript
                                        
  <Directory /path/to/rails/public>                                                         
      Order allow,deny                                                                                  
      Allow from all                                                                                    
      AllowOverride All                                                                                 
  </Directory>                                                                                          
</VirtualHost>

Zu guter Letzt noch eine 304 Weiterleitung für die, die “http://site.stefanwienert.net” oder “http://stefanwienert.net” eintippen. Das ganze kann man in die entsprechenden htaccess packen oder oben gleich mit bei den “Directory” Direktiven mit angeben. Hier der Vollständigkeit halber, bevor ihr selbst erst googlen müsst.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# /var/www/.htaccess:
RewriteEngine On

RewriteCond %{HTTP_HOST} ^stefanwienert.net$
RewriteCond %{REQUEST_URI} ^\/$
RewriteRule ^(.*)$ http://www.stefanwienert.net/$1 [R=permanent,L]


# /path/to/rails/public/.htaccess
RewriteEngine on

RewriteCond %{HTTP_HOST} ^site.stefanwienert.net [NC]
RewriteRule ^(.*)$ http://www.stefanwienert.net/$1 [L,R=301]


# Hups, hier sieht man mal, dass ich die Zeilen jeweils woanders
# herkopiert habe: Selbe Funktion aber etwas andere Syntax :)

Vim 7.2 mit ERB HAML .. Syntaxhightlighting auf Debian Squeeze

Wer sein Rails Projekt auf Debian laufen hat, und seine Minichanges mit VIM macht, der kennt vielleicht das Problem, dass bei Vim 7.1 keine Syntax Beschreibungen fuer ERB und HAML (z.B.) dabei sind.

7.2. kann man wie folgt installieren (Alternativ aber auch aus der Quelle, hier jetzt mit den debs)

1
2
3
4
5
6
7
# Pakete herunterladen
wget http://ftp.de.debian.org/debian/pool/main/v/vim/vim-common_7.2.330-1_i386.deb
wget http://ftp.de.debian.org/debian/pool/main/v/vim/vim-runtime_7.2.330-1_all.deb
wget http://ftp.de.debian.org/debian/pool/main/v/vim/vim_7.2.330-1_i386.deb  

# Das Zeug installieren
dpkg -i *.deb

Jetzt ist es zwar schon installiert, aber u.a. das Syntaxhighlighting sollte noch etwas bocken, weil noch der runtimepath angepasst werden muss:

1
2
3
4
5
6
7
vim /usr/share/vim/vimrc

# Dort unten einfuegen, falls die Zeile in der Datei nicht vorhanden ist:
set runtimepath=~/.vim,/etc/vim,/usr/share/vim/vimfiles,/usr/share/vim/addons,/usr/share/vim/vim72,\
   /usr/share/vim/vimfiles,/usr/share/vim/addons/after,~/.vim/after

# Speichern und raus

Sollte soweit klappen. Bitte einen Kommentar hinterlassen, falls was schiefgelaufen ist.

Rails/Passenger im Parallels Plesk zum Laufen bekommen

Wer auch Parallels Plesk Panel für seine Serveradministration verwendet, und sich schonmal gefragt hat, ob es was besseres als die Build-in Fast CGI Unterstützung oder Mongrel/Webrick gibt, dem will ich hier mal einen kleinen Guide geben, wie das ganze mit Passenger zu bewerkstelligen ist.
Wir verwenden für die Administration unserer Server auch Plesk, da es echt stupid simple ist.

Ich gehe davon aus, dass Ruby und Rubygems bereits installiert sind! (Sollte man z.B. Debian verwenden, auf keinen Fall die Pakete aus dem apt-get installieren, sondern manuell wie hier beschreiben.) Auch ein Root-Zugang zum Server wird benötigt.

Also:

  1. im Plesk eine neue Domain/Subdomain anlegen
  2. Unser Rails-Projekt nach /var/www/vhosts/DOMAIN/httpdocs bzw. /var/www/vhosts/DOMAIN/subdomains/SUBDOMAIN/httpdocs kopieren. Also genau dort rein, kein weiteres Unterverzeichnis (nach httpdocs kommen dann gleich app db config public …)
  3. Schauen, dass die Lese/Schreibrechte hinhauen: z.B. chgrp psaserv log db tmp -R && chmod g+w * -R. Im einzelnen mal schauen.
  4. Root Konsole: Gems installieren und Datenbank migrieren:
1
2
3
4
5
rake gems:install
rake db:migrate RAILS_ENV="production"
gem install passenger
# laengere Anleitung befolgen. Im Endeffekt muss man ein paar Zeilen in die apache2.conf kopieren. 
# Den zweiten Teil mit mit der Vserver Konfiguration interessiert uns im Moment nicht
  1. Im Ordner DOMAIN/conf also von unserem httpdocs Verzeichnis ../conf/vhost.conf nun die Datei vhost.conf anlegen und folgendes reinkopieren (jeweils das richtige Verzeichnis als Ziel nehmen, je nachdem ob wir eine Subdomain oder Domain benutzen möchten):
1
2
3
4
5
6
 DocumentRoot /var/www/vhosts/DOMAIN/httpdocs/public
# bzw.   /var/www/vhosts/DOMAIN/subdomains/SUBDOMAIN/httpdocs/public
 <Directory /var/www/vhosts/pludoni.de/subdomains/tasks/httpdocs/public >
    AllowOverride all
    Options -MultiViews
 </Directory>
  1. plesk Vhost reloaden:
1
/usr/local/psa/admin/sbin/websrvmng -u --vhost-name=DOMAIN.de

hierbei jeweils immer nur die Domain angeben, auch wenn wir nur einen Subdomain anlegen.

Nun sollte unsere Rails App unter der Domain bzw. Subdomain verfügbar sein. Neustarten können wir Passenger indem wir ein touch tmp/restart.txt oder die Datei sonst irgendwie im Timestamp verändern.

Kurzes Gem Showcase - Delicious, actsasarchive, menu borwsercms css sprite

Ich schaue gerade meine kürzlich gebookmarkten Sites an, und will hier mal ein paar coole Ruby Ressourcen zeigen.

  • Delicious-API: http://github.com/weppos/www-delicious für den beliebten Bookmarkdienst
  • Acts as archive, destroy und delete Aktionen eines Objektes führen nicht zur Löschung, sondern Archivierung http://github.com/winton/acts_as_archive
  • MMMenu http://github.com/snitko/mmmenu eine kleine Menü DSL)
  • Automatische, transparente CSS Sprite Transformation http://github.com/reevoo/spriter
  • BrowserCMS, meine Basis CMS für meine nächsten Projekte http://www.browsercms.org/
    Schaut euch das Video dazu an

und sowieso:
http://www.ruby-toolbox.com/ und http://www.rubyflow.com/ zur Ideenfindung.

I love that community :)

Umgang und Mapping einer Legacy Datenbank mit Ruby (ohne Rails) mit abweichenenden Namenskonventionen mit Active Support

Einleitung/Motivation

Zur Zeit moechte ich verschiedene XML-Dialekte aus einem vorhandenen Datenbankschema gewinnen, und brauchte dazu ein ordentliches Objektrelationales Mapping, wie man es aus Rails ja kennt. (Ausprobieren! keine Zeile SQL mehr notwendig :D).
Allerdings ohne Rails sondern in einem einfachen Rubyscript.
Was es dort alles gibt, will ich hier mal kurz exemplarisch vorfuehren.

Voraussetzung und Datenbankverbindung

Um ein Legacy relationales Datenmodell mit Ruby schoen zu mappen, ging ich letztens wie folgt vor:

Zu erst Rails (active_record ist aber auch ausreichend) installieren, falls noch nicht gemacht (fuer active_record) und composite primary keys, das uns wie der Name schon sagt, zusammengesetzte Primärschlüssel, welches unser Legacy-Schema mitunter mit sich bringt, bereitstellt.

1
sudo gem install rails composite_primary_keys 

Nun können wir uns im ersten Schritt mit unserer Datenbank verbinden:

1
2
3
4
5
6
7
8
9
10
11
require "rubygems"
require "active_record"
require "composite_primary_keys"

options = {:adapter  => 'mysql',
      :database => 'databasename',
      :username => 'username',
      :password => '******',
      :host     => 'localhost' ,
      :encoding => 'utf8'}
ActiveRecord::Base.establish_connection(options)

Definition der Modelle

Nun kommt dort drunter die Konstruktion der Modell-Klassen, die die Tabellen abbilden.

Angenommen wir haben eine Tags, Posts, Posts_Tags und Users Tabelle (in freier Ruby Namenskonvention) mit den folgenden Beziehungen:
Post : Tag = n : m (Jobs_Tags)
Post : User = n : 1

Also ein Post hat eine Anzahl Tags (über “jobs_tags”) und genau einen User.

Da das aber zu leicht wäre, gibt es folgende Handicaps :):

  • “Posts” Tabelle heißt “entries_import”, Primaerschluessel (PK) postid, Fremdschlüssel “uid” heißt “nutzer”
  • “Tags” Tabelle heißt “clouds_import”, PK tagid
  • “Posts_Tags” Tabelle heisst “clouds_import_lnk”, PK (postid,tagid) zusammengesetzter Primaerschluessel!
  • “Users”-Tabelle heißt “users”, mit PK uid

(leicht abgeändertes RealWorld Beispiel!)

Tja sieht schon recht messy aus. Aber alles machbar:

Der Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class Post < ActiveRecord::Base
  set_table_name "entries_import"  # posts Tabelle
  set_primary_key "postid"
  has_many :tags, :through => :taggings
  has_many :taggings, :primary_key => "postid", :foreign_key => "postid"
  belongs_to :user,  :foreign_key => "nutzer"

# Extra Points! Unser 'Post' hat ein "visible" Attribut, welches 
# geradezu nach einem named scope schreit! :)
   named_scope :visible, :conditions => {:visible => 1}, :order => "pubDate desc"


#Extra Points! Tags direkt als (Komma)getrennte Liste zurueckgeben lassen, und 
# noch den Tag "Blog" auf jeden Fall ans Ende der Tags haengen
  def tag_list(sep = ",")
    (tags.map(&:name) << "Blog").uniq.join(sep)
  end
end

class Tag < ActiveRecord::Base
  set_table_name "clouds_import"
  set_primary_key "tagid"
  has_many :jobs, :through => :taggings
  has_many :taggings, :primary_key => "tagid", :foreign_key => "tagid"
end

class Tagging < ActiveRecord::Base
  set_table_name "clouds_import_lnk"
  set_primary_keys :jobid, :tagid  # Zusammengesetzter Primaerschluessel
  belongs_to :job, :primary_key => "postid", :foreign_key => "postid"
  belongs_to :tag, :primary_key => "tagid", :foreign_key => "tagid"
end

class User < ActiveRecord::Base
  set_primary_key "uid"
  set_table_name 'users'
  has_many :jobs, :foreign_key => "nutzer", :primary_key => "uid"
end

Fertig!
Nun können wir in althergebrachter Rails Manier extrem bequem auf unsere Modelle wie folgt zugreifen:

1
2
3
4
5
6
7
8

posts = Post.all
posts.first.tags  #  gibt uns die tags zurück
post = Post.find(:first, :order => "...")
post.user.name

# oder auch named scopes (siehe oben)
Post.visible.first.tag_list

usw. Wirklich eine Wohltat ;)

Natürlich kann man in seinen Modellen noch Methoden definieren, die uns den Zugriff noch erleichtern und unser Modell um Funktionalität erweitert und damit unsere Controller und Views nicht zumuellt.

Bonus: XML Builder

Wie man jetzt damit einen XML-Dialekt (z.B. auch RSS) baut, ist recht einfach, dank des XML Builder Gems (Das bei Rails eigentlich auch schon dabei sein sollte).
Ich will hier nur ganz kurz teasern, ansonsten.. Google ist dein Freund:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
require "rubygems"
require "builder"

xml = Builder::XmlMarkup.new( :target => $stdout , :indent => 1 )
xml.instruct!
xml.rss do  
# oder:  xml.tag!("rss") do   sinnvoll falls unser Tag nicht nur aus Kleinbuchstaben besteht
  xml.channel do
    for item in Post.visible
       ...
       ... item.title  ...
      
    end
  end
end

Tool fuer externe/interne Link-Analyse mit rel=nofollow

Fuer ein aktuelles Projekt wurde eine Linkanalyse, insbesondere der ausgehenden Links gewuenscht. Insbesondere die Verwendung des SEO Buzzwords “rel=nofollow” sollte dabei aufgezeigt werden. Was lag naeher als schnell in Ruby mit Zuhilfenahme des hpricot Gems ein kleines Skript dafuer zu bauen?

Das Skript gruppiert die Links in die drei Kategorien “Internal, External with nofollow, External without nofollow”. Hintergrund ist hierbei, dass das nofollow Attribut Suchmaschinen anweist, den verlinkten Seiten bei der Berechnung ihres Pagerankes diesen Link zu ignorieren. Mehr Infos in der Wikipedia. Anmerken moechte ich noch, dass die Verwendung des Attributes umstritten ist, ich persoenlich finde es relativ ueberfluessig; Warum verlinkt man eine Seite, nur um den Suchmaschinen zu sagen, “hey, ich hab jetzt aber nicht auf die Seite verlinkt”.

Dank XML Builder ist dann auch ein ordentlicher XML Export kein Problem, und laesst sich so mit z.B. Firefox bequem navigieren.

Unter linkcheck/link_check_form findet ihr ein minimalistisches Eingabeformular. Das Ganze laesst sich natuerlich auch bequem mit GET ansteuern :).

PHP - Die beste Wahl für's Web?

Eines vorneweg: PHP war mein Einstieg in die Webprogrammierung. Die ersten Schritte haben, aufgrund der C-ähnlichen und mir damit bekannten Syntax, sogar sehr Spaß gemacht.

Nicht ganz ausschweigen sollte man den Fakt, dass eine Skriptsprache ganz gleich welcher Rubrik natürlich nicht das Allheilmittel jeglicher Softwareprojekte ist, weshalb ich mich hier ganz klar auf Sprachen für (private und kleinkommerzielle) Webentwicklung beschränken möchte.

Story

Wenn man wie ich von PHP kommt, ist bei Ruby und Rails vieles am Anfang ungewöhnlich, und es braucht seine Zeit, bis man sich an den Fakt, das alles ein Objekt ist, gewöhnen muss. Dies schafft aber auch erstklassige Möglichkeiten, Programmtext effizient und damit übersichtlich zu gestalten.

Im Gegensatz zu PHP wo ich bei trivialsten Dingen jedesmal das Rad neu erfinden muss (Ich denke nur an DateTime Handling, fortgeschrittene Stringfunktionen) hat Rails und Ruby eine sehr ausdrucksstarke Bibliothek dabei.
Schön finde ich diese Grafiken. Hiernach wurden für PHP-Projekte deutlich mehr Line of Codes am Gesamtkuchen gezählt, die meiste Zunahme an Projekten überhaupt gegeben hat. Also man für eigentlich alle Projekte unter PHP eine Wagenladung Code mitbringen muss. DRY FTW.
Auch die extrem bunte Bibliothek von PHP, die scheinbar über die Jahre aus C-Sprachen zusammengeklaut wurde, mit total uneinheitlichen Verhalten von Funktionen: usort verändert sein Argument und gibt nichts zurück, str_replace belässt es und gibt das Ergebnis zurück.

Die Syntax — Showdown

Der Fakt der C-Abstammung ist für mich einer der größten Kritikpunkte, denn intuitiv ist was anderes (strstr zum Finden eines Strings…, bei Ruby: find).
Wenn ich mal wieder ein etwas größeres Modul in Drupal beginn, vergesse ich so manches mal ein “;”.
Das nervt und ist absolut unnötigt. Mehr als eine Anweisung ist nur für Obfascuation-Wettbewerbe geeignet. Desweiteren ist das “;” trotzdem unter Ruby optional nutzbar.

Warum diese extreme Anlehnung der Syntax an den C-Sprachen? Ist sie für betriebssystemnahe Anwendungsfälle recht angebracht, da minimal abstrakt, führt sie beim Anwendungsfallszenario “Webentwicklung” doch mehr Hürden denn Erleichterungen.

Warum wie ein Computer denken? Wenn ich doch wie ein Mensch denken kann? Für ein kleines µ mehr an Performance? Dafür mit einer deutlich angestiegenen Fehleranfälligkeit, teilweise unüberschaubaren Programmfluss und einer grottigen Wartbarkeit?

Klar ist es toll, wenn man vorher C, C++, Java oder was auch immer programmiert hat, kurz mal PHP sieht, und denkt “Hey, das ist ja genau das gleiche!”. Auch ich hatte diesen Aha-Effekt (Im Rückblick nichts, gegen den Aha-Effekt, den ich z.B. bei der ersten Nutzung der script/console, dem ersten scaffold oder der Validate <—> Formularfehlermeldung hatte :D)

PHP ist in meinen Augen als Websprache absolut ungeeignet.

Viele gute PHP-Frameworks wie CakePHP, Zend oder auch auch in erweiterter Bedeutung Drupal, können meiner Ansicht nach nicht über diesen Aspekt hinwegtäuschen.

Hier ein paar Auszüge meiner Lieblingshassobjekte:

1
2
3
4
htmlspecialchars   <--->   h
$this->            <--->   Warum muss man diese 
Redundanz innerhalb einer Klasse mit sich herumschleppen? 
Warum "weiß" die Klasse nicht direkt über ihre Methoden?

Weitere Vorteile ergeben sich aus der kompletten Objektorientierung:

1
2
str_replace("a","b","Hallo");       <---> "Hallo".gsub("a","b")
preg_match("/../",$source,$target); <---> target = /.../.match(source)

Im Endeffekt ist PHP sowas von laberlastig und ausdrucksschwach, dass ich z.B. bei der Entwicklung von Drupal-Modulen ohne Snippets überhaupt nicht mehr klarkommen würde. Klar liegt es vielleicht auch ein stückweit an Drupal, nichsdestotrotz bietet die aufgepfropfte Objektorientierung auch hier keine Erleichtung.

But it’s a complex language that contains a lot of advanced idioms which will be very hard for PHP and Visual Basic programmers to absorb.

Sometimes, too much magic is too much magic, and it can definitely be the case that the flow of code is too direct or too clever to be understandable by regular developers. Developers were able to do the jump from imperative to object-oriented programming, but it was a hard fight.

Quelle

Die vielerorts kritisierte scheinbar komfortable Konvertierung von PHP hat auch bei mir schon zu so manchen erstaunlichen Programmverhalten geführt.

Durch Rails habe ich aber auch die korrekte Benennung meiner Modelle und Datenbanktabellen gelernt. Also wenn ich eine Nutzer-Tabelle habe, dann heißt sie “users”, der Primärschlüssel “id”, ein Nutzerfremdschlüssel einer anderen Tabelle würde “user_id” heißen.
Warum? Bei Rails wird man für die korrekte Benennung “belohnt”, indem einige Dinge komplett automatisch passieren, sollte man sich an die Konventionen gehalten haben. Dazu zählt: Benutzung von “partials” (Also eines View-Code-Schnipsels, dass für jedes Item eines Objekts einmal ausgeführt wird),

Manch einer mag anführen, dass Syntax Geschmackssache ist, und bei der Bewertung einer Sprache nur einen Teilaspekt darstellen sollte. Dem stimme absolut nicht zu. Je mehr Sonderzeichen ( “{ } ; $”) im Textfluss sind, desto schwerer lässt es sich lesen.

Rails Fanboy for life?

Auch bei Ruby oder Rails ist (natürlich wie immer in meinen Augen) nicht alles perfekt: neidisch blicke ich auf die Einrücksemantik von Python, spart sie mir doch die Blockschlüsselwörter. Oder das von Haus aus installierte “erb” finde ich durch “haml” erst erträglich gemacht :).

Auch habe ich ständig das Gefühl, dass ich erst einen Bruchteil der Sprache voll ausschöpfe. Insbesondere die funktionalen Aspekte wie procs habe ich bisher nur selten verwendet.
Auch die sehr mächtigen Testmöglichkeiten durch gems wie rspec, cucumber oder silenium habe ich bisher eher akademisch benutzt.

In vielen Foren habe ich auch von einem fast schon spürbaren Hass auf Rails-Nutzer bemerkt; da wird von “Latte-Machiatto schlürfende” “Fanboys” geredet, die nur “oberflächliche” Anwendungen programmieren [können]. Kein Vergleich mit JavaEE, C, whatsoever. Das mag sein, dass ein Railsprojekt nicht unbedingt als System für eine Forbes 100 Firma geeignet ist, aber für sehr viele Anwendungsfälle, insbesondere bei überschaubaren Websites, mit nicht ganz 100% mainstreammäßigen also individuell Anforderungen (“Blog”, also Wordpress, Mini social Community Drupal, usw) ist es in vielerlei Hinsicht eine bessere Wahl als… PHP.
Schön gesagt von xaviershay auf github:

No ugly PHP Stylings burning your eyeballs.

Quelle

Ganz ausgelassen habe ich hierbei Django/Python, dass ganz oben auf meiner Liste der zu begutachtenden Frameworks steht.

Fazit?

Ja ich bin subjektiv.
Vielleicht liegt es an dem gut gemachten Screencast von Ryan Bates und teach-me-code? Oder der per Plugins (wirble, hirb) aufgemöbelten Liveshell irb bzw. script/generate, die mir so manchen “Ausprobier”-Lauf erspart hat (Kein Vergleich mit php -a )? Oder an dem teils humorig geschrieben Buch von O’Reilly? Oder an der Wahl der Namen? (“god” das Monitoring Tool, “sass:Syntactically awesome Stylesheets”, “YAML”: Yet another markup language", hpricot also wie Aprikose…)?
Ruby/Rails verbreitet einfach eine andere Grundstimmung – Die Leute haben Spaß beim Programmieren!

Redmin - Full Blown Rails Bugtracking Anwendung

Kürzlich war ich auf der Suche nach einer guten Bugtracking Anwendung. Über den Weg gelaufen sind mir dabei:

welche ich mir alle drei angeschaut habe.

Mein absoluter Favorit ist Redmine, welches auch eine Rails Application ist :).
Vom Umfang entspricht es genau dem, was ich mir wünschte:

  • Verwaltung mehrere Projekte, öffentlich und nicht-öffentlich
  • Feature Requests
  • Taskverwaltung/Roadmap und Berichte für abgeleistete Stunden
  • E-Mail Benachrichtigung bei Statusänderungen, neuen Bugs
  • E-Mail API zum Antworten

Meiner Ansicht nach für die meisten kleineren bis mittelgroßen Projekten absolut ausreichend. Nicht mehr und nicht weniger.

Anmerkung Da Redmine Rails ist, war hier meiner Meinung nach die Installation am leichtesten; git clone, database.yml und migrate und einen neuen Eintrag für Apache/Passenger.
Ganz im Gegensatz zu Bugzilla, welche als Perl Anwendung mich erst einmal vor größere Probleme stellte :).