MyHolidays.com Seminararbeit mit Ruby on Rails Author: Fabian Merki
Inhaltsverzeichnis Idee...3 Implementierung...4 Tipps & Tricks...5 Combobox...5 Passwörter...5 Kein 'show'...5 Layouts...6 Problem: HTML-Tags in Formular-Input...6 Plugins & Co...7 Google-Maps Plugin...7 Login Generator...7 Where Plugin...8 Fazit...9 Fabian Merki 05.11.2006 2 von 9
Idee Wer erinnert sich noch nach 20 Jahren an all seine Feriendestinationen? Dank MyHolidays.com vergisst man diese nie mehr! So etwa könnte der Werbeslogan für mein Ruby Projekt lauten. Dank dem öffentlichen API von Google Maps lassen sich diverse Applikationen mit Landkarten realisieren. Mit einer Datenbank, welche Benutzer, Feriendestinationen und Ferien beinhaltet, lassen sich Karten mit Markers erweitern. So könnte zum Beispiel eine Ferienkarte aussehen: Fabian Merki 05.11.2006 3 von 9
Implementierung Die Implementation dieses Projekts erfolgte in Ruby on Rails. Die Datenbank enthält die Entitäten Users, Holidays, Locations und LocationTypes. Das Grundgerüst konnte ich generieren lassen. Jedoch waren dann einige Änderungen notwendig, bis die Applikation folgendes unterstütze: Der Benutzer muss sich anmelden (signup & login) und kann dann seine Holidays und Locations editieren. Der Benutzer kann seine und die Ferienübersicht von anderen anschauen. Nur der Administrator (zur Zeit user.login == merkisoft) kann die Benutzerdaten und LocationTypes editieren. Zusätzlich musste ich zum Beispiel das Suchen der Adressen und das Setzten der Markers in der Karte in JavaScript lösen. Ich habe die Applikation nur unter Internet Explorer 6 getestet Probleme mit andern Browsern sind leider (fast) zu erwarten... Fabian Merki 05.11.2006 4 von 9
Tipps & Tricks Rails und Scaffold sind recht genial. Aus der Datenbank lassen sich innert wenigen Schritten ganze Applikationen entwickeln. Danach muss man 'nur' noch ein paar Änderungen vornehmen welche durchaus ein paar Stunden in Anspruch nehmen können, falls man sich nicht so gut auskennt. Folgende Tipps und Tricks sollen helfen diese Zeit zu verkürzen. Combobox Leider erstellt Scaffold nicht automatisch Comboboxen für Fremdschlüsselfelder. Eine Combobox ist aber sehr schnell in _form.rhtml programmiert: <p><label for="holiday_location_id">location</label><br> <%= select("holiday", "location_id", @locations.collect { lt [ "#{lt.name}, #{lt.address}", lt.id ] })%> Passwörter Scaffold hat automatisch das Passwort als Passwortfeld in 'edit' dargestellt. In 'list' und 'show' wurde dies jedoch als normaler Text angezeigt. Folgender Code <%=h @user.send(column.name) %> habe ich mit diesem Code ersetzt: <%=h @user.send(column.name) if column.name!= "password" %> <%=h "********" if column.name == "password" %> Somit ist das Passwort nur noch als ******** ersichtlich. Kein 'show' Ich persönlich finds schöner, wenn man nach dem Editieren direkt wieder auf der Übersichtsliste landet. In der 'update' Methode im Controller findet man folgende Zeile: redirect_to :action => 'show', :id => @location Diese ersetzt man durch redirect_to :action => 'list' und schon ist die Applikation etwas einfacher und schneller zu bedienen. Wer will kann auch noch in list.rhtml und edit.rhtml die 'Show'-Links entfernen sowie die show.rhtml Dateien löschen. Fabian Merki 05.11.2006 5 von 9
Layouts Damit man immer das gleiche Layout hat, sollte man in den Controllern das Layout fix angeben: layout 'scaffold' Damit wird die Datei views/layouts/scaffold.rhtml auf allen Seiten verwendet. Problem: HTML-Tags in Formular-Input Ein häufiges Problem bei Web-Seiten ist, dass man HTML-Tags in Formularen und somit in die Datenbank speichern kann. Zwar unterstützt uns Rails mit dem Befehl: <%=h @holiday.description%> Hiermit wird der HTML-Code dargestellt; das heisst, dass <b> als Text <b> angezeigt wird und nicht die Zeichenformatierung auf fett gesetzt wird. Leider werden '\n' nicht automatisch durch <br> ersetzt. Für das Feld 'description' in Holiday habe ich dies folgendermassen gelöst: # class Holiday before_create :descupdate before_update :descupdate def descupdate write_attribute("description", description.split("<").join("[")) end Und erst bei der Anzeige in HTML werden die '\n' durch <br> (HTML-Tag für Zeilenumbruch) ersetzt. Somit ist die Datenbasis immer noch für Reports etc. benutzbar. # show.rhtml <%=@holiday.description.split("\n").join(" <br>")%> Fabian Merki 05.11.2006 6 von 9
Plugins & Co. Google-Maps Plugin Bei der Installation des Plugins hatte ich mit einigen Schwierigkeiten zu kämpfen. Der Secure-Download schlug immer mit einem SSLError fehl. Nachdem ich die Plugins google_maps und unbacked_dom_id (nötig für google_maps) direkt mittels Subversion ins Verzeichnis 'vendor/plugins/' heruntergeladen habe, musste ich das init.rb von google_maps folgendermassen anpassen: require 'google_map' require File.dirname( FILE ) + '/lib/google_map' Zudem gabs noch Dependency-Probleme mit unbacked_dom_id beim Starten des Servers. Um nicht noch mehr Zeit damit zu verlieren habe ich die Datei unbacked_dom_id.rb einfach ins google_maps/lib Verzeichnis kopiert. Für die Konfiguration war lediglich der Eintrag des Keys im environment.rb nötig: GOOGLE_APPLICATION_ID = "ABQIAAAA3HdfrnxFAPWyYaiJUxmqRTJQa0g3IQ9GZqIMmInSLzwtGDKaBQ0KYLwBEKSM7F9gCevcsIf6WPuIQ" Dieser erhält man bei Google. Der oben verwendete ist für localhost gültig. Login Generator Auf folgenden Seiten ist der Login-Generator bestens beschrieben: http://wiki.rubyonrails.org/rails/pages/howtoquicklydoauthenticationwithlogingenerator http://wiki.rubyonrails.com/rails/pages/logingenerator http://wiki.rubyonrails.com/rails/pages/readme_login User-Authorisation kann man zum Beispiel mit folgendem Code in den Controller-Klassen erreichen: def authorize?(user) user.name!= "merkisoft" end Fabian Merki 05.11.2006 7 von 9
Where Plugin Dieses Plugin konnte ich ohne Mühe installieren, da ich nun Subversion richtig installiert hatte und es ohne https erreichbar ist. ruby script/plugin install http://invisible.ch/svn/projects/plugins/where Nun kann man sehr einfach SQL-Abfragen für 'list' schreiben. Anstatt alle Datensätze anzuzeigen @holiday_pages, @holidays = paginate :holidays, :per_page => 10 schreibt man nun: @holiday_pages = Paginator.new self, Holiday.count, 15, params[:page] id = @session['user'].id @holidays = Holiday.find_with_conditions(:all, :order => 'start', :limit => @holiday_pages.items_per_page, :offset => @holiday_pages.current.offset) do user_id id end Der Paginator ist für das Paging verantwortlich, find_with_conditions erhält einen Block in welchen man das Query schreibt. 'user_id id' bedeutet, dass 'user_id' gleich 'id' sein muss. Fabian Merki 05.11.2006 8 von 9
Fazit Mit Ruby on Rails lassen sich super schnell Web-Applikationen entwickeln. Aber auch hier versteckt sich der Teufel im Detail. So war es ohne Buch über Rails nicht immer ganz einfach herauszufinden, wie man zum Beispiel das Login, das 'Includen' von rhtml, das Erweitern von Formularen umsetzt. Dank Google und vielen guten Seiten ist es mir dennoch gelungen. Auch der Einsatz von Google-Maps war nicht mühelos, hat sich aber auf jeden Fall gelohnt. Mit Hilfe meiner Erfahrung und dieses Dokumentes wäre ich nun sicherlich in der Lage weitere Web-Applikationen mit Ruby on Rails ohne grossen Zeitaufwand zu schreiben. Es ist einfach genial, wie häufig man sich auf Ruby und Ruby on Rails verlassen kann. Vermutlich würde ich das nächste Mal versuchen Rails Templates von Beginn an auf meine Bedürfnisse anzupassen, damit ich danach noch schneller entwickeln kann und nicht ständig den rhtml- und Ruby-Code anpassen muss. Fabian Merki 05.11.2006 9 von 9