Mephisto per Capistrano deployen

Jun 2008
24

0 Kommentar(e)

Eingetragen von Martin Maciaszek

Nach dem Ausfall des Servers letzte Woche, mußte ich dieses Blog auf einem neuen Server aufsetzen. Ein passender Augenblick, das ganze sauber mit Capistrano zu machen. Dies ist eine kurze Zusammenfassung, wie auch du Mephisto auf einem Server mit openSuSE 10.2 und Plesk 8.4 (wie sie bei 1&1 angeboten werden) deployen kannst. Die Beispiele haben “acts-as-blog.net” als Beispieldomain. Du solltest entsprechend die Daten deinen Anforderungen anpassen.

Den ganzen Artikel lesen

Building PostgreSQL on Mac OS X Leopard

Mar 2008
27

1 Kommentar(e)

Eingetragen von Martin Maciaszek

Some time ago I wrote a german article on how to install PostgreSQL on Leopard. It seems I struck a chord with many people. So I decided to make this article accessible to a wider audience by translating it to English. I modified and updated parts of it where appropriate. So here it is without further ado.

Den ganzen Artikel lesen

Plugin der Woche: active_record_defaults

Feb 2008
28

0 Kommentar(e)

Eingetragen von Martin Maciaszek

Ein Plugin, was mir heute ein wenig Arbeit erspart hat ist active_record_defaults. Damit kann man in ActiveRecord-Modellen Defaultwerte für einzelne Attribute festlegen, ohne sie im Schema zu verankern. Das Plugin findet sich unter http://svn.viney.net.nz/things/rails/plugins/active_record_defaults/. Die Benutzung ist denkbar einfach:

class Person < ActiveRecord::Base
  defaults :age => 16
end

Schon ist jede Person 16 Jahre alt, sofern nichts anderes angegeben wurde.


Rails 2.0

Dec 2007
07

1 Kommentar(e)

Eingetragen von Martin Maciaszek

Holt es euch, solange es heiß ist!

Eine recht ausführliche Liste aller Neuerungen gibt es hier.

Ich werde mal gleich eine kleine Testanwendung versuchen. Mal schauen, wie es sich anfühlt.

Update: 2.0.1 ist bereits raus. Ist wohl beim Release etwas schiefgelaufen.


PostgreSQL auf Mac OS X 10.5

Nov 2007
04

17 Kommentar(e)

Eingetragen von Martin Maciaszek

Vor einer Weile habe ich in meinem Blog geschrieben, wie man PostgreSQL auf Mac OS X 10.4 (aka Tiger) installiert. Seitdem ist eine Weile ins Land gegangen. PostgreSQL ist inzwischen bei 8.2.5 angekommen und es existiert eine 8.3 beta 2. Nicht ganz unerwähnt bleiben sollte auch die Tatsache, daß vor kurzem Mac OS X 10.5 (aka Leopard) erschien. Änderungen in Mac OS X 10.5 machen haben dazu geführt, daß meine alte Anleitung als überholt angesehen werden kann. Deshalb folgt hier die aktualisierte Version.

Den ganzen Artikel lesen

simply_helpful in Rails Edge

Oct 2007
19

0 Kommentar(e)

Eingetragen von Martin Maciaszek

Und noch eine Arbeitserleichterung in Rails Edge (und damit auch im kommenden Rails 2.0). Simply Helpful war bislang als Plugin für Rails 1.2.x verfügbar. In Verbindung mit REST sind Formulare jetzt noch einfacher zu schreiben. In Rails 1.2.x muß man noch folgendes schreiben, um ein Edit-Formular zu bekommen:

form_for :foo, @foo, :url => foo_path(@foo), :html => {:method => :put} do |f|
  ...
end

Das geht nun deutlich kürzer:

form_for @foo do |f|
  ...
end

Jepp, das ist alles. Simply Helpful erkennt automatisch, ob es sich bei @foo um ein neues ActiveRecord-Objekt handelt und baut automagisch einen Link zur create- bzw. update-Action.


Partials jetzt noch einfacher

Oct 2007
18

0 Kommentar(e)

Eingetragen von Martin Maciaszek

Und wo ich gerade bei Änderungen in Rails Edge bin. Eine weitere fingerschonene Änderung hat es in Rails geschafft. Mußte man bislang noch folgendes schreiben:

render :partial => "projects", :collection => @projects

genügt demnächst schon:

render :partial => @projects

FormHelper#label in Rails Edge

Oct 2007
18

0 Kommentar(e)

Eingetragen von Martin Maciaszek

Seit Changeset 7541 hat Rails Edge (und damit höchstwahrscheinlich auch das kommende Rails 2.0) einen neuen Helper, um Labels für Formularfelder zu erzeugen. Hier ist ein kleines Beispiel, um zu sehen, wie der Helper benutzt werden kann.

<% form_for(:foo, @foo, :url => foo_path(@foo)) do |f| -%>
  <%= f.label :bar, 'Bar' %>
  <%= f.text_field :bar %>
<% end -%>

Läßt man den zweiten Parameter hinter label weg, so wird die Beschriftung aus dem Attributnamen mit humanize abgeleitet.


Rails-Plugins mit Piston

Oct 2007
16

0 Kommentar(e)

Eingetragen von Martin Maciaszek

Ein Rails-Projekt ohne Plugins ist nahezu undenkbar. Plugins wie attachment_fu, restful_authentication und will_paginate sind fast immer Pflicht. Mit script/plugin, was bei jedem Rails-Projekt beiliegt, können diese Plugins installiert werden.

Das script/plugin-Skript funktioniert recht gut, hat jedoch ein paar Schönheitsfehler. Standardmäßig kopiert es einfach alle Dateien in ein Verzeichnis in vendor/plugins/mein_plugin. Ein update des Plugins ist so jedoch unmöglich. Es kann nur erneut installiert werden. Dabei werden etwaige eigene Änderungen am Plugin gnadenlos überschrieben.

Um diesem Problem entgegenzuwirken, kann script/plugin mit der Option -x aufgerufen werden. Das Plugin wird dann mit Subversion als External ausgecheckt. Dies löst das Problem mit den Updates. Sollte jedoch das externe Repository nicht erreichbar sein, so wird Subversion Fehlermeldungen beim update und commit ausspucken. Grafische Frontends für Subversion kommen mit diesen Fehlermeldungen selten klar. Auch wer von der Kommandozeile arbeitet, wird auf die Dauer von diesen Fehlermeldungen genervt sein.

An dieser Stelle kommt Piston ins Spiel. Es checkt die Plugins aus ohne externals, vermerkt jedoch für sich, woher das Plugin stammt. Damit ist ein Update jederzeit möglich. Und da sich Subversion nicht um externals kümmern muß, ist es auch kein Problem, wenn das externe Repository nicht erreichbar ist.

Piston wird wie jedes andere Gem einfach mit gem install piston -y installiert. Damit ist es nun einsatzbereit. Benötige ich nun will_paginate in meinem Projekt, so installiere ich es einfach mit folgendem Befehl:

piston import svn://errtheblog.com/svn/plugins/will_paginate \
   vendor/plugins/will_paginate

Um dieses Plugin auf den neuesten Stand zu bringen benutze ich dann diesen Befehl:

piston update vendor/plugins/will_paginate

Weitere Optionen finden sich auf der Piston-Website.


Deployment mit Capistrano

Sep 2007
28

1 Kommentar(e)

Eingetragen von Martin Maciaszek

Ein Rails-Projekt mit Capistrano zu deployen ist eigentlich gar nicht so schwer. Es kann jedoch leicht passieren, daß man einen Schritt vergißt und dann erstmal dumm aus der Wäsche schaut. Deshalb habe ich mal kurze Anleitung hier geschrieben, wie der grundsätzliche Ablauf aussieht. Ich setze Capistrano 2.0 ein. Wer noch die Vorgängerversion (1.4.x) einsetzt sollte sein Gem updaten, um dieser Anleitung zu folgen.

Projekt capistranisieren

Um ein Rails-Projekt mit Capistrano zu deployen, brauchst du zu allererst das Capistrano-Gem. Dies kannst du mit gem install capistrano -y installieren. Auf dem Zielserver (auf den das Projekt deployed werden soll) benötigst du außerdem noch Subversion. Ich muß hoffentlich nicht extra erwähnen, daß ein Zugriff per ssh auf den Zielserver Pflicht ist? Damit sollte alles installiert sein, was du benötigte. Capistranisiere dein Projekt mit capify. In meinem Beispiel sieht dies so aus:

[~] capify /Users/fastjack/Sites/DrawBridge
[add] writing `./Capfile’
[add] writing `./config/deploy.rb’
[done] capified!

Auf die Plätze

In der config/deploy.rb mußt du Capistrano mitteilen, wohin es dein Projekt beim Deployment befördern soll. Die Konfiguration sieht bei mir in etwa so aus:

set :application, "DrawBridge"
set :repository,  "http://svn.meinserver.irgendwo/DrawBridge/trunk"

role :app, "192.168.1.182"
role :web, "192.168.1.182"
role :db,  "192.168.1.182", :primary => true

set :deploy_to, "/usr/local/www/frigg/#{application}"
set :use_sudo, false

namespace :deploy do
  desc "upload database configuration"
  task :add_database_configuration, :roles => :web do
    run "mkdir -p #{shared_path}/config"
    config = File.read(File.join(File.dirname(__FILE__), "database.yml"))
    put config, "#{shared_path}/config/database.yml"
    run "ln -s #{shared_path}/config/database.yml \
          #{latest_release}/config/database.yml"
  end

  after "deploy:finalize_update", "deploy:add_database_configuration"
end

Mit dieser Konfiguration wird Capistrano mein Projekt auf den Server mit der IP-Adresse 192.168.1.182 unter /usr/local/www/frigg/DrawBridge befördern. Capistrano wird hierzu einen Checkout mit Subversion durchführen. Der Subversion-Server sollte also vom Zielserver erreichbar sein. Zu guter Letzt wird noch die Datenbankkonfiguration von meinem Rechner auf den Zielserver kopiert (weil ich die Datenbankkonfiguration nicht in das Repository einchecke). Damit sollte auch klar sein, daß die config/database.yml einen Abschnitt für die production-Umgebung besitzen muß, der auf dem Zielserver funktioniert.

Damit Capistrano nach dem Deployment auch den Mongrel starten kann, brauchst du noch ein spin-Skript im scripts-Verzeichnis. Dieses sollte ausführbar sein und auch als ausführbar in Subversion (svn propset svn:executable on script/spin) markiert sein. Mein script/spin sieht so aus:

#!/bin/sh
script/process/spawner -a 127.0.0.1 -p 15000 -i 3

Damit werden 3 Mongrel-Server auf den Ports 15000-15002 gestartet, die nur auf Anfragen vom Localhost reagieren. Die Mongrels werden bei mir hinter einem Apache, der als Proxy fungiert, laufen, deshalb sind sie auch nur an den Localhost gebunden.

Fertig

Damit ist hoffentlich alles bereit, um das Projekt zu deployen. Mit cap deploy:check kannst du noch schnell prüfen, ob es irgendwelche schwerwiegenden Probleme gibt, die das Deployment behindern könnten. Warnmeldungen über ein Fehlendes releases-Verzeichnis kannst du dabei ignorieren, dies wird im nächsten Schritt angelegt. Nun ist es an der Zeit, das Deployment vorzubereiten. Mit cap deploy:setup läßt du Capistrano die noch fehlenden releases- sowie shared-Verzeichnisse anlegen. Überprüfe noch schnell, ob du auch wirklich alle lokalen Änderungen wieder ins Repository eingecheckt habst, sonst werden sie nicht auf den Zielserver gelangen.

Los!

Jetzt kann es losgehen. Mit cap deploy:cold startest du nun den Deploymentprozess. Dies dauert ein paar Minuten und endet hoffentlich damit, daß am Ende folgende Zeilen stehen:

[192.168.1.182] executing command
** [out :: 192.168.1.182] appending output to nohup.out
   command finished

Nun laufen 3 Instanzen des Mongrels und warten auf Anfragen vom Apache.

Herzlichen Glückwunsch. Dein Projekt wurde erfolgreich deployed. Lehn dich zurück und genieße ein erfrischendes (alkoholisches) Getränk.


Resourcen im Singular

Sep 2007
24

0 Kommentar(e)

Eingetragen von Martin Maciaszek

Wer sich in Rails über die etwas unverständliche Fehlermeldung wie diese wundert session_url failed to generate from {:controller=>"session", :action=>"show"} - you may have ambiguous routes, or you may need to supply additional parameters for this route. content_url has the following required parameters: ["session", :id] - are they all satisfied?, der hat mit Sicherheit in seiner routes.rb folgendes stehen:

map.resources :session

Das Problem dabei ist, daß die Resource session im Singular ist, während die map.resources-Anweisung eine Resource im Plural erwartet. Schreibt man stattdessen:

map.resource :session

so klappt es auch wieder mit dem Routing. (Ja, es ist nur das Plural-s verschwunden).


Autotest, Growl und RSpec

Sep 2007
18

0 Kommentar(e)

Eingetragen von Martin Maciaszek

Ich hatte einen ähnlichen Artikel bereits in meinem anderen Blog darüber geschrieben. Doch hier ist es nochmal, damit alles an einem Ort zu finden ist, und weil ich in der Zwischenzeit auch einiges daran geändert habe.

Angenfangen hat es, als ich ein paar Wochen über diesen Artikel von John Nunemaker in meinem Feed-Reader gestolpert bin. Das war gleich doppelt interessant. Ich fand die Idee mit Growl supergeil. Und von autotest hatte ich bis dahin auch noch nie gehört. Autotest ist Teil des ZenTest-Gems und kann ganz einfach mit gem install ZenTest -y installiert werden. (Die meisten werden noch ein sudo davor schreiben müssen)

Nachdem ich meine erste ~/.autotest-Datei erstellt habe, ging das eigentliche Experimentieren erst richtig los. Ich war nicht der einzige, der über diesen Artikel gestolpert war, denn kurze Zeit später präsentierte Jamie Hill etwas ansehnlichere Icons. Das sah schon richtig gut aus. Zu guter Letzt machte mein Wechsel auf RSpec einige Änderungen notwendig. Meine derzeitige ~/.autotest-Datei sieht also so aus. (download)

require 'autotest/timestamp'

module Autotest::Growl

  IMAGE_ROOT = "~/Library/Autotest/Images" 

  def self.growl title, msg, img, pri=0, sticky="" 
    system "growlnotify -n autotest --image #{img} -p #{pri} -m '#{msg}' '#{title}' #{sticky}" 
  end

  def self.find_test_summary(test_results)
    test_summary = test_results.find {|result| result.include? "example"}.chomp
  end

  def self.display_test_summary(summary)
    examples, failures, pending = summary.split(', ')
    if failures.to_i > 0
      growl "Tests fehlgeschlagen", summary, "#{IMAGE_ROOT}/fail.png", 2
    elsif pending.to_i > 0
      growl "Tests stehen aus", summary, "#{IMAGE_ROOT}/pending.png", 1
    else
      growl "Tests bestanden", summary, "#{IMAGE_ROOT}/pass.png", 0
    end
  end

  Autotest.add_hook :ran_command do |at|
    unless at.results.empty?
      summary = find_test_summary(at.results)
      display_test_summary(summary)
    else # Irgendwas ging ganz furchtbar schief
      growl "Panik!", "Die Tests lieferten keine Ergebnisse!", "#{IMAGE_ROOT}/panic.png", 3
    end
  end
end

Ich habe die Smileys um einen vierten Panic-Smiley ergänzt, falls etwas ganz fürchterlich schief gehen sollte. Da ich autotest immer in Netbeans starte und die Netbeans-Konsole keine Farbcodes beherrscht, entferne ich in meinen Projekten in $PROJEKT/spec/spec.opts immer die Zeile mit --colour. Folglich habe ich es auch nicht für nötig befunden, diese Farbcodes in meiner ~/.autotest-Datei herauszufiltern. Wem die Growl-Nachrichten nicht bunt genug sind, und auch farbige Meldungen in der Konsole haben möchte, muß sich einen entsprechenden Filter selbst in seine ~/.autotest-Datei einbauen.


Validations und virtuelle Attribute

Sep 2007
11

0 Kommentar(e)

Eingetragen von Martin Maciaszek

Manchmal möchte ich (virtuelle) Attribute im Model haben, die sich nicht 1:1 auf Spalten in einer Tabelle abbilden lassen. Ein gutes Beispiel dafür ist mein Machine-Model. In dem Model möchte ich unter anderem das Baujahr der Maschine festhalten. Dies könnte ich zwar auch einfach als ein Integer in der Datenbank speichern, doch für diverse Datumsberechnungen habe ich mich dazu entschlossen, das Baujahr als Datum (jeweils als den 1. Januar des Jahres) zu speichern. Das Baujahr habe ich zu einem virtuellen Attribut es Models gemacht. Das ganze sieht dann so aus.

class Machine < ActiveRecord::Base
  def build_year
    read_attribute(:built_on).year if read_attribute(:built_on)
  end

  def build_year=(year)
    write_attribute(:built_on, Date.new(year.to_i, 1, 1)) unless year.empty?
  end
end

Damit läßt sich nun build_year wie jedes andere Attribut des Models in Views verwenden. Wie wäre es noch mit Validations? Hierzu habe ich folgende validate-Methode gebaut.

def validate
  errors.add(:build_year, "can't be blank") unless build_year.is_a?(Fixnum) 
  errors.add(:build_year, "must be after 1944") if build_year && build_year<1945
  errors.add(:build_year, "can't be in the future") if build_year && build_year>Date.today.year
end

Damit wird mein virtuelles Attribut nun auch entsprechend im View hervorgehoben, wenn die Validation fehlschlägt.


content_for und Defaultwerte

Sep 2007
01

0 Kommentar(e)

Eingetragen von Martin Maciaszek

Mit content_for lassen sich mehrere Bereiche im Layout mit Inhalten füllen. Typischerweise sieht das im View so aus.

<% content_for :page_title do -%>
  Niemand erwartet die Spanische Inquisition
<% end -%>

Im Layout kann ich nun das ganze mit yield :page_title wieder ausgeben. Was ist aber wenn ich gar keinen Inhalt für den :page_title angebe? Dann kommt die Seite mit einem leeren Titel daher. Daher ist es sinnvoll, hier einen Defaultwert anzugeben. Das könnte im Layout etwa so aussehen.

<%= (yield :page_title) || "Du hast den Titel vergessen, du Dummy!" %>

Alternativ könnte ich auch einen Partial hier einbinden, aber das hängt ganz von den Anforderungen ab.


Doppelt hält besser

Sep 2007
01

0 Kommentar(e)

Eingetragen von Martin Maciaszek

Ich benutze oft einen recht nützlichen Rubyismus, den ich bang-bang nenne. In meinem fiktiven User-Modell habe ich folgende Methode.

def married?
  !! spouse
end

Die Methode spouse würde hier einfach nur eine Instanz des User-Models mit dem Ehepartner zurückgeben. Aber was sollen die beiden Ausrufezeichen (in Unix-Kreisen als bang bezeichnet) da? Ein Ausrufezeichen in Ruby ist normalerweise eine logische Negation. Zwei Ausrufezeichen sind also eine doppelte Negation.

Wer in der Schule aufgepasst hat, wird nun einwerfen, daß eine doppelte Negation sich selbst wieder aufhebt. Das ist auch korrekt, doch in Ruby gelten etwas andere Regeln. Alles was nicht false oder nil ist, gilt als wahr. Liefert also die Methode spouse einen Ehepartner zurück, so gibt die Methode married? das Ergebnis true zurück.