<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Christoph Bünte &nbsp;&raquo; Software Entwicklung Berlin</title>
	<atom:link href="http://www.christophbuente.de/tag/ruby-on-rails/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.christophbuente.de</link>
	<description>Software Entwicklung</description>
	<lastBuildDate>Tue, 07 Dec 2010 11:30:07 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.5</generator>
		<item>
		<title>Rails Hosting bei Rocket Rentals &#8211; auch mit Staging Umgebung</title>
		<link>http://www.christophbuente.de/2010-07-20-rails-hosting-bei-rocket-rentals-auch-mit-staging-umgebung/</link>
		<comments>http://www.christophbuente.de/2010-07-20-rails-hosting-bei-rocket-rentals-auch-mit-staging-umgebung/#comments</comments>
		<pubDate>Tue, 20 Jul 2010 09:19:09 +0000</pubDate>
		<dc:creator>Christoph Bünte</dc:creator>
				<category><![CDATA[howto]]></category>
		<category><![CDATA[Apache]]></category>
		<category><![CDATA[Capistrano]]></category>
		<category><![CDATA[deployment]]></category>
		<category><![CDATA[hosting]]></category>
		<category><![CDATA[passenger]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[Ruby on Rails]]></category>
		<category><![CDATA[staging]]></category>
		<category><![CDATA[Virtualhost]]></category>

		<guid isPermaLink="false">http://www.christophbuente.de/?p=449</guid>
		<description><![CDATA[Mein aktuelles Projekt an dem ich arbeite ist wheelmap.org. Wheelmap.org stellt eine Anwendung für Rollstuhlfahrer bereit, die es ihnen ermöglicht herauszufinden, welche Orte rollstuhlgerecht sind, und welche nicht. So werden Orte aufgezeigt, welche Fahrst&#252;hle, abgesenkte Bordsteinkanten oder auch sogenannte Rollstuhllifte anbieten. Wheelmap wird auf den Server von Rocket Rentals gehostet. Die Jungs von Rocket Rentals [...]]]></description>
			<content:encoded><![CDATA[<p>Mein aktuelles Projekt an dem ich arbeite ist <a title="Rollstuhlgerechte Orte finden" href="http://wheelmap.org">wheelmap.org</a>. Wheelmap.org stellt eine Anwendung für Rollstuhlfahrer bereit, die es ihnen ermöglicht herauszufinden, welche Orte rollstuhlgerecht sind, und welche nicht. So werden Orte aufgezeigt, welche Fahrst&uuml;hle, abgesenkte Bordsteinkanten oder auch <a href="http://www.lifta.de/treppenlift/rollstuhllift.html">sogenannte Rollstuhllifte</a> anbieten. Wheelmap wird auf den Server von <a title="To the web and back" href="http://www.rocket-rentals.de/de/">Rocket Rentals</a> gehostet. Die Jungs von Rocket Rentals bieten neben Rails Hosting auch <a title="CoWorking bei Rocket Rentals" href="http://www.rocket-rentals.de/coworking">Co-Working Space</a> und professionelle Anwendungsentwicklung.<br />
Da ich hauptsächlich in meinem Büro entwickle, besteht die Notwendigkeit in regelmässigen Abständen meinen Fortschritt zu präsentieren. Und das möglichst auf einem Server im Netz und nicht auf meiner Entwicklungsmaschine. Dafür eignet sich die Live Anwendung allerdings schlecht. Kleinere Fehler oder unvollständige Features möchte man nicht auf den echten Benutzer loslassen. Deswegen habe ich eine Staging Umgebung eingerichtet, die jeweils den aktuellen Entwicklungsstand zeigt. Die Live Umgebung läuft weiterhin nur mit einer stabilen Version. Und so gehts:<span id="more-449"></span>Als erstes muss in DNS Konfiguration eine Subdomain eingerichtet werden. Das ist von Rocket Rentals unabhängig und sollte durch den DNS Provider oder auf dessen Weboberfläche vorgenommen werden. In meinem Fall ist die Domain: <a href="http://staging.wheelmap.org">staging.wheelmap.org</a></p>
<p><img class="alignleft size-medium wp-image-460" style="margin: 5px;" title="screenshot_admin_rocket_rentals" src="http://www.christophbuente.de/wp-content/uploads/screenshot_admin_rocket_rentals-300x147.jpg" alt="screenshot_admin_rocket_rentals" width="300" height="147" /> Damit der Rocket Rentals Server richtig auf den Request reagieren kann, muss im Admin Frontend ebenfalls eine Subdmain angelegt werden. Dazu logged man sich unter beim <a title="Rocket Rentals Login" href="https://login.rocket-rentals.de:8080/">Hosting</a> ein. Im oberen Menü wählt man &#8220;Sites&#8221;. Aus dem linken Menü wählt man dann &#8220;Subdomain&#8221; aus. Das Host Feld beinhaltet den Namen der Subdomain. Der Redirect Type ist &#8220;No flag&#8221;. Der Redirect Path ist &#8220;/&lt;subdomain&gt;_&lt;domain&gt;_&lt;tld&gt;&#8221;. Beispiel: &#8220;/staging_wheelmap_org&#8221;. Nach dem Speichern dauert es höchstens 15 Minuten, bis die Änderungen aktiv sind. In der Zwischenzeit können wir aber schon eine neue Datenbank anlegen. Das ist besonders wichtig, da wir nicht die Produktivdatenbank versehentlich verändern wollen, wenn die Auftraggeber die neue Version ausprobieren und dabei Daten manipulieren. Auch das kann auf der Admin Seite des Rocket Rentals Frontend geschehen. Usernamen und Passwort für die Datenbank nicht vergessen!</p>
<p>Dann muss auf dem Rechner, der das deployment durchführt eine Capistrano Erweiterung installiert werden:</p>
<pre lang="bash&quot;">sudo gem install capistrano-ext</pre>
<p>Danach muss die deploy.rb Datei etwas angepasst werden. Füge folgende Zeilen an den Anfang der Datei:</p>
<pre lang="ruby"># config/deploy.rb

set :stages,        ['staging', 'production']
set :default_stage, 'staging'
require 'capistrano/ext/multistage'</pre>
<p>Jetzt werden für jede Umgebung im Rails Projekt unter config/deploy/ eine eigene Datei mit dem Umgebungsnamen angelegt:</p>
<pre lang="bash">mkdir -p config/deploy
touch config/deploy/staging.rb
touch config/deploy/production.rb</pre>
<p>Aus der bisherigen deploy.rb Datei müssen folgende Zeilen in die config/deploy/production.rb kopiert werden:</p>
<pre lang="ruby"># config/deploy/production.rb

set :application, 'domain_tld' # Beispiel: wheelmap_org
set :db_names, :production =&gt; 'prod_db_name'
set :db_user, 'prod_db_username'
set :db_password, 'prod_db_password'
set :rails_env,   'production'</pre>
<p>Anschließend müssen diese Zeilen in der config/deploy.rb auskommentiert oder gelöscht werden.</p>
<p>In der config/deploy/staging.rb Datei müssen jetzt die Angaben für die Staging Umgebung gemacht werden:</p>
<pre lang="ruby"># config/deploy/staging.rb

set :application, 'subdomain_domain_tld' #Beispiel: staging_wheelmap_org
set :db_names, :production =&gt; 'staging_db_name'
set :db_user, 'staging_db_username'
set :db_password, 'staging_db_password'
set :rails_env,   'staging'</pre>
<p>Nun sind alle Vorbereitungen getroffen und wir können die Staging Umgebung einrichten:</p>
<pre>cap staging deploy:setup</pre>
<p>Danach kann die Anwendung deployed werden:</p>
<pre>cap staging deploy:cold</pre>
<p>Will man die Live Version deployen führt man folgenden Befehl aus:</p>
<pre>cap production deploy</pre>
<p>Bei Problemen oder Fragen einfach einen Kommentar hinterlassen.</p>
<div id="crp_related"><h3>Ähnliche Beiträge:</h3><ul><li><a href="http://www.christophbuente.de/2007-11-25-ruby-on-rails-auf-mac-os-x-5-minuten-kurzanleitung/" rel="bookmark" class="crp_title">Ruby on Rails auf Mac OS X &#8211; 5 Minuten Kurzanleitung</a></li><li><a href="http://www.christophbuente.de/2007-11-17-canoo-webtest-web-anwendungen-automatisch-testen/" rel="bookmark" class="crp_title">canoo webtest &#8211; Web-Anwendungen automatisch testen</a></li><li><a href="http://www.christophbuente.de/2007-11-24-advancing-rails-ein-workshop-mit-david-a-black/" rel="bookmark" class="crp_title">Advancing Rails &#8211; Ein Workshop mit David A. Black</a></li><li><a href="http://www.christophbuente.de/2007-12-21-voiceglue-konfiguration-server-fur-sprachanwendungen-einrichten/" rel="bookmark" class="crp_title">VoiceGlue Konfiguration &#8211; Server für Sprachanwendungen einrichten</a></li><li><a href="http://www.christophbuente.de/2008-07-01-mysql-myisam-index-oder-nicht/" rel="bookmark" class="crp_title">MySQL MyISAM &#8211; Index oder nicht?</a></li></ul></div>]]></content:encoded>
			<wfw:commentRss>http://www.christophbuente.de/2010-07-20-rails-hosting-bei-rocket-rentals-auch-mit-staging-umgebung/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Opensocial Gadgets &#8211; Apps für StudiVZ selbst entwickeln</title>
		<link>http://www.christophbuente.de/2009-10-29-opensocial-gadgets-apps-fur-studivz-selbst-entwickeln/</link>
		<comments>http://www.christophbuente.de/2009-10-29-opensocial-gadgets-apps-fur-studivz-selbst-entwickeln/#comments</comments>
		<pubDate>Thu, 29 Oct 2009 19:39:51 +0000</pubDate>
		<dc:creator>Christoph Bünte</dc:creator>
				<category><![CDATA[Web Entwicklung]]></category>
		<category><![CDATA[backend]]></category>
		<category><![CDATA[beispiel]]></category>
		<category><![CDATA[example]]></category>
		<category><![CDATA[gadgets]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[meinvz]]></category>
		<category><![CDATA[opensocial]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[Ruby on Rails]]></category>
		<category><![CDATA[schuelervz]]></category>
		<category><![CDATA[studivz]]></category>
		<category><![CDATA[Tutorial]]></category>
		<category><![CDATA[widgets]]></category>

		<guid isPermaLink="false">http://www.christophbuente.de/?p=399</guid>
		<description><![CDATA[Wie StudiVZ bereits angekündigt hat, werden die ersten opensocial Anwendungen für ihre Plattform bald live gehen. Entwickler können sich schon jetzt registrieren und ihre so genannten Gadgets in einer Sandbox ausprobieren. Ich habe das Vergnügen für meinen aktuellen Kunden DaWanda ein Gadget für StudiVZ zu entwickeln. Ein Gadget besteht aus einer XML Datei, die definiert, [...]]]></description>
			<content:encoded><![CDATA[<p>Wie <a href="http://developer.studivz.net/2009/09/24/opensocial-is-now-available-in-our-vz-sandbox/">StudiVZ</a> bereits angekündigt hat, werden die ersten <a href="http://code.google.com/intl/de-DE/apis/opensocial/">opensocial</a> Anwendungen für ihre Plattform bald live gehen. Entwickler können sich schon jetzt registrieren und ihre so genannten Gadgets in einer Sandbox ausprobieren.</p>
<p>Ich habe das Vergnügen für meinen aktuellen Kunden <a href="http://www.dawanda.com">DaWanda</a> ein Gadget für StudiVZ zu entwickeln. Ein Gadget besteht aus einer XML Datei, die definiert, um welche Anwendung es sich handelt, wer der Author ist usw. Dazu gehören wahlweise mehrere CSS und Javascript Dateien. Nachdem man alles in eine Zip Datei, die den gleichen namen wie die XML Datei trägt, gepackt hat, kann man die Anwendung in die Sandbox hochladen und ausprobieren. Eine Beispiel Datei könnte so aussehen:</p>
<pre escaped="true" lang="xml">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;Module&gt;
  &lt;ModulePrefs
    title="Example StudiVZ Gadget"
    title_url="http://www.christophbuente.de"
    author="Christoph Bünte"
    author_email="info@christophbuente.de"
    description="Example description"
    screenshot="http://www.christophbuente.de/images/screenshot.jpg"
    thumbnail="http://www.christophbuente.de/images/thumbnail.jpg"&gt;
    &lt;Require feature="opensocial-0.8" /&gt;
    &lt;Require feature="views" /&gt;
  &lt;/ModulePrefs&gt;
  &lt;Content type="html" &gt;
    &lt;![CDATA[
      &lt;script&gt;
        function init() {
          // Put initialization code here
        }
        gadgets.util.registerOnLoadHandler(init);
      &lt;/script&gt;
    &lt;div id='container'&gt;&lt;/div&gt;
    ]]&gt;
  &lt;/Content&gt;
&lt;/Module&gt;</pre>
<p><span id="more-399"></span><br />
Jede Interaktion des Benutzers mit der Anwendung wird mit Hilfe weiterer Javascript Funktionen behandelt. Dazu stehen eine Reihe eingebauter Funktionen aus dem Opensocial Container bereit. Darüber hinaus haben die Entwickler von StudiVZ eine <a href="http://developer.studivz.net/wiki/index.php/Gadgets_API">API Beschreibung</a> der zusätzlichen Funktionen bereit gestellt. Was aber, wenn man nun nicht mit Javascript entwickeln möchte bzw. kann? Es besteht die Möglichkeit Flash Content einzubinden. Man kann aber auch ein beliebiges Backend einbinden. Dieses Backend muss nur 2 Bedingungen erfüllen:</p>
<ul>
<li>Es muss auf <acronym title="Hypertext Transfer Protocol">HTTP</acronym> Requests reagieren können und beliebiges <acronym title="Hypertext Markup Language">HTML</acronym>,<acronym title="Cascading Style Sheet">CSS</acronym> und JavaScript zurück liefern</li>
<li>Es muss im Namen des Applikationsbenutzers einen OAuth signierten Request an die StudiVZ <acronym title="Representational State Transfer">REST</acronym> <acronym title="Application Programming Interface">API</acronym> schicken können.</li>
</ul>
<p><a href="http://www.christophbuente.de/wp-content/uploads/Bild-7.png"><img class="size-full wp-image-419 alignleft" title="Request Opensocial Backend" src="http://www.christophbuente.de/wp-content/uploads/Bild-7.png" alt="Schema: Request Opensocial Backend" width="348" height="376" /></a><br />
Wie im Schema zu sehen, sendet der User einen Request, um die Applikation zu benutzen. Der Container liest darauf hin den Inhalt der XML Datei aus. Dort ist neben einem DIV Container lediglich ein externes Javascript referenziert. In dem Javascript sind einfache Methoden zum Navigieren und Interagieren definiert. Das rendern des HTML übernimmt ein Ruby Backend. Das braucht zum Render unter Umständen noch zusätzliche Informationen wie zum Beispiel Name und Foto des Benuter usw. Diese Informationen holt es sich mit einem OAuth signierten Request von der abgebildeten REST API. Das vom Ruby Backend erzeugte HTML rendert der Opensocial Container in einem IFrame im Browser des Benutzers. Für eine bessere Übersicht definieren wir im XML einzelne Views, die jeweils einen eigenen Endpunkt im Backend haben. Eine einfache gadget.xml mit 2 definierten Views für Profil und Vollansicht mit Backend Anbindung:</p>
<pre escaped="true" lang="xml">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;Module&gt;
  &lt;ModulePrefs
    title="Spitzenmässiges StudiVZ Gadget mit Backendanbindung"
    title_url="http://www.christophbuente.de"
    author="Christoph Bünte"
    author_email="info@christophbuente.de"&gt;
    &lt;Require feature="opensocial-0.8" /&gt;
    &lt;Require feature="views" /&gt;
  &lt;/ModulePrefs&gt;
  &lt;Content type="html" view="profile" &gt;
    &lt;![CDATA[
      &lt;script type="text/javascript" src="http://www.yourbackend.com/profile.js" &gt;&lt;/script&gt;
      &lt;div id='profile'&gt;&lt;/div&gt;
    ]]&gt;
  &lt;/Content&gt;
  &lt;Content type="html" view="canvas" &gt;
    &lt;![CDATA[
      &lt;script type="text/javascript" src="http://www.yourbackend.com/canvas.js" &gt;&lt;/script&gt;
      &lt;div id='canvas'&gt;&lt;/div&gt;
    ]]&gt;
  &lt;/Content&gt;
&lt;/Module&gt;</pre>
<p>Das referenzierte Javascript ist ebenfalls sehr schlank. Darin wird lediglich eine Backend URL aufgerufen und deren Response Body in das profile bzw. canvas div geschrieben.</p>
<pre>function init{
  var url = 'http://www.yourbackend.com/profile/'
  var params = {};
  params[gadgets.io.RequestParameters.AUTHORIZATION]=gadgets.io.AuthorizationType.SIGNED;
  gadgets.io.makeRequest(url, requestCallback, params);

}

function requestCallback(obj) {
	document.getElementById('profile').innerHTML = obj.data;
}</pre>
<p>Damit die REST API benutzt werden kann, muss man sich an ihr Authentifizieren. Da das Backend aber dumm ist, hat es keine Userdaten, um sich dort anzumelden. Glücklicherweise ist der Request aus dem Javascript mit dem verschlüsselten Authentifierungsdaten des angemeldeten Anwendungsbenutzers signiert. Mit deren Hilfe können wir einen neuen, signierten Request erzeugen, den die API akzeptieren wird. Doch zuerst muss die Glültigkeit der Signatur überprüft werden:</p>
<p><code>sudo gem install oauth --source http://gemcutter.org</code></p>
<pre lang="ruby">
require 'oauth'
require 'oauth/consumer'
require 'oauth/request_proxy/action_controller_request'
require 'oauth/signature/rsa/sha1'
require 'oauth/signature/hmac/sha1'

class ApplicationController < ActionController::Base

  before_filter <img src='http://www.christophbuente.de/wp-includes/images/smilies/icon_surprised.gif' alt=':o' class='wp-smiley' /> auth_required

  def oauth_required
    cert_file = File.join(RAILS_ROOT, 'public', 'public.cer')
    cert_str = File.read(cert_file)
    consumer = OAuth::Consumer.new(ConsumerToken, cert_str)

    begin
      pass = OAuth::Signature.build(request, :consumer => consumer).verify
      logger.info "Signature verification returned: #{pass}"
    rescue OAuth::Signature::UnknownSignatureMethod => e
      logger.error "ERROR "+ e.message
    end

    render :text => "OAuth access denied", :status => :unauthorized  unless pass
  end
</pre>
<p>Die URL für das öffentliche Zertifikat wird mit jedem Request mit geschickt. Einmal runterladen sollte reichen. Ich denke, man muss es nicht bei jedem Request erneut vom StudiVZ Server laden. Den Consumer Token findet ihr in der OAuth Section eurer Gadget Sandbox (http://www.meinvz.net/GadgetDeveloper/GadgetOAuth/xxx). xxx ist deine Gadget ID.</p>
<p>Sollte der before_filter nicht abbrechen war die Signatur korrekt und der Request kann bearbeitet werden. Aus einem mir nicht bekannten Grund ist der Request des Containers an das Backend mit der RSA-SHA1 Methode signiert. Dafür wird das Zertifikat benötigt. Für den Request an die API muss die HMAC-SHA1 Methode verwendet werden. Dafür wird ein neuer Consumer benötigt:</p>
<pre lang="ruby">def get_owner
  consumer = OAuth::Consumer.new(ConsumerToken, ConsumerSecret,
      :signature_method => 'HMAC-SHA1',
      :site => "http://sandbox.gadgets.apivz.net",
      :scheme => :query_string,
      :http_method => :get)
  requestor_param = {:xoauth_requestor_id => params[:opensocial_owner_id]}.to_param
  access_token = OAuth::AccessToken.new(consumer)
  response = access_token.get("/social/rest/people/#{params[:opensocial_owner_id]}/@self?#{requestor_param}")
  owner_attributes = JSON.parse(response.body)['entry']
end</pre>
<p>Feedback, Fragen und Kritik sind immer gerne willkommen.</p>
<div id="crp_related"><h3>Ähnliche Beiträge:</h3><ul><li><a href="http://www.christophbuente.de/2007-11-10-paypal-subscriptions-abonnements-in-java-integrieren/" rel="bookmark" class="crp_title">Paypal subscriptions &#8211; Abonnements in Java integrieren</a></li><li><a href="http://www.christophbuente.de/2010-07-20-rails-hosting-bei-rocket-rentals-auch-mit-staging-umgebung/" rel="bookmark" class="crp_title">Rails Hosting bei Rocket Rentals &#8211; auch mit Staging Umgebung</a></li><li><a href="http://www.christophbuente.de/2007-10-23-bots-aussperren-mit-captcha/" rel="bookmark" class="crp_title">captcha tutorial &#8211; Bots aussperren</a></li><li><a href="http://www.christophbuente.de/2007-12-06-voiceglue-installation-interactive-voice-response-leicht-gemacht/" rel="bookmark" class="crp_title">VoiceGlue Installation &#8211; Interactive Voice Response leicht gemacht</a></li><li><a href="http://www.christophbuente.de/2007-11-17-canoo-webtest-web-anwendungen-automatisch-testen/" rel="bookmark" class="crp_title">canoo webtest &#8211; Web-Anwendungen automatisch testen</a></li></ul></div>]]></content:encoded>
			<wfw:commentRss>http://www.christophbuente.de/2009-10-29-opensocial-gadgets-apps-fur-studivz-selbst-entwickeln/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Remarkable &#8211; Rails Anwendungen automatisch testen</title>
		<link>http://www.christophbuente.de/2009-05-16-remarkable-rails-anwendungen-automatisch-testen/</link>
		<comments>http://www.christophbuente.de/2009-05-16-remarkable-rails-anwendungen-automatisch-testen/#comments</comments>
		<pubDate>Sat, 16 May 2009 10:14:17 +0000</pubDate>
		<dc:creator>Christoph Bünte</dc:creator>
				<category><![CDATA[Testing]]></category>
		<category><![CDATA[cucumber]]></category>
		<category><![CDATA[functional test]]></category>
		<category><![CDATA[integration test]]></category>
		<category><![CDATA[model validation]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[remarkable]]></category>
		<category><![CDATA[rspec]]></category>
		<category><![CDATA[Ruby on Rails]]></category>
		<category><![CDATA[testspec]]></category>
		<category><![CDATA[unit test]]></category>
		<category><![CDATA[validation test]]></category>

		<guid isPermaLink="false">http://www.christophbuente.de/?p=251</guid>
		<description><![CDATA[Seit über einem Jahr entwickle ich Webanwendungen mit Ruby on Rails. Und seit dieser Zeit schreibe ich Tests für meine Anwendungen. Angefangen von Test::Unit über test/spec bis zu RSpec. Doch selten gingen mir Tests leicht von der Hand. Ständig stelle ich mir die Frage: Wie viel teste ich? Habe ich genug getestet? Teste ich schon [...]]]></description>
			<content:encoded><![CDATA[<p><!--noadsense--><br />
Seit über einem Jahr entwickle ich Webanwendungen mit Ruby on Rails. Und seit dieser Zeit schreibe ich Tests für meine Anwendungen. Angefangen von <a href="http://api.rubyonrails.org/classes/Test/Unit/Assertions.html">Test::Unit</a> über <a href="http://test-spec.rubyforge.org/test-spec/">test/spec</a> bis zu <a href="http://rspec.info/">RSpec</a>. Doch selten gingen mir Tests leicht von der Hand. Ständig stelle ich mir die Frage: Wie viel teste ich? Habe ich genug getestet? Teste ich schon Rails Code?</p>
<p>Die verschiedenen Test Frameworks haben ihre Vor- und Nachteile. Test::Unit ist relativ einfach und schnell. test/spec und RSpec hingegen deutlich lesbarer, jedoch auch langsamer. Sie eigenen sich deshalb besser, um die Tests als Dokumentation zu verwenden. Test::Unit und test/spec verwenden für Viewtests den Umweg über die Controller, was sie im Vergleich zu RSpec deutlich langsamer macht. In Rspec testet man jede Schicht des <acronym title="Model View Controller">MVC</acronym> Musters separat. Das Verhalten der jeweils anderen Schichten wird mit Mocks und Stubs simuliert. Integration Tests mit Cucumber testen dann das Zusammenspiel aller Schichten.</p>
<p><a href="http://github.com/carlosbrando">Carlos Dandos</a> und <a href="http://github.com/josevalim">José Valims</a> <a href="http://github.com/carlosbrando/remarkable/tree/master">Remarkable</a> ist das mit Abstand großartigste Plugin für <a href="http://rubyonrails.org/">Ruby on Rails</a>, was mir seit langem über den Weg gelaufen ist, denn es reduziert Tests auf das nötigste! Man schreibt in unglaublich expressiver Form, was das erwartete Verhalten ist. Das auf RSpec basierende Remarkable testet mit einer Vielzahl von Custom Matchers die Erwartung ab.</p>
<p><span id="more-251"></span></p>
<p>Ein Beispiel für ein Model Validation Test in Test::Unit</p>
<pre escaped="true" lang="ruby" line="1">class UserTest &lt; Test::Unit
  def test_user_not_valid_if_name_is_blank
    user = User.create
    assert user.invalid?
    assert_equal :blank, :user.errors[:name]
  end
end</pre>
<p>Ein Beispiel für ein Model Validation Test in test/spec</p>
<pre escaped="true" lang="ruby">context 'User validations' do
  specify 'user should not be valid if name is blank' do
    user = User.create
    user.should.not.be.valid
    user.errors[:name].should == :name
  end
end</pre>
<p>Ein Beispiel für ein Model Validation Test in RSpec</p>
<pre escaped="true" lang="ruby">describe User do
  it 'should not be valid if name is blank' do
    user = User.create
    user.should_not_be_valid
    user.errors[:name].should == :blank
  end
end</pre>
<p>Und jetzt der gleiche Test mit Remarkable:</p>
<pre escaped="true" lang="ruby">describe User do
  it { should validate_presence_of(:name) } # RSpec syntax
  should_validate_presence_of :name # Remarkable macro syntax
end</pre>
<p>Ok, was musst du tun, um Remarkable verwenden zu können? Falls noch nicht geschen, solltest du das Gem Verzeichnis von <a href="http://gems.github.com">Github</a> als Quelle für weitere Gems lokal registrieren:</p>
<pre lang="bash">sudo gem sources -a http://gems.github.com</pre>
<p>Danach müssen die benötigten Gems installiert werden:</p>
<pre lang="bash">sudo gem install rspec -v 1.2.6
sudo gem install rspec-rails -v 1.2.6
sudo gem install remarkable_rails</pre>
<p>Für alle, die noch eine Rails Version &lt; 2.2 verwenden müssen zusätzlich den <a href="http://github.com/svenfuchs/i18n/tree/master">I18n Backport von Sven Fuchs</a> installieren:</p>
<pre lang="bash">sudo gem install svenfuchs-i18n</pre>
<p>Abschließend müssen im Rootverzeichnis des entsprechenden Rails Projektes noch einige helper scripte generiert werden:</p>
<pre lang="bash">ruby script/generate rspec</pre>
<p>Welche Matcher bringt Remarkable mit?</p>
<ul>
<li>Matcher für <em>alle</em> Validierungen mit <em>allen</em> Optionen</li>
<li>Matcher für <em>alle</em> Assoziationen mit <em>fast allen</em> Optionen</li>
<li>Named Scopes und Massenzuweisungsmatchern</li>
<li>Datenbank Matcher für Indexes usw.</li>
</ul>
<p>Ein typischer Unit Test mit Remarkable könnte so aussehen:</p>
<pre escaped="true" lang="ruby">require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')

describe User, 'validations' do
  should_validate_presence_of   :username, :email, :password
  should_validate_length_of     :username, :minimum =&gt; 6
  should_validate_acceptance_of :agreement
end

describe User, 'associations' do
  should_have_many :images
  should_have_many :posts
  should_have_one  :profile
end

describe User, 'database' do
  should_have_column :activated, :type =&gt; :boolean
  should_have_index  :username
end

describe User, 'named scopes' do
  should_have_scope :with_image, :joins =&gt; :images
  should_have_scope :activated,  :conditions =&gt; { :activated =&gt; true }
end</pre>
<p>Und von nun an möchte ich nicht mehr hören, dass testen zu schwer sei. Alles Ausreden!</p>
<p>In diesem Sinne, Test frei.</p>
<div id="crp_related"><h3>Ähnliche Beiträge:</h3><ul><li><a href="http://www.christophbuente.de/2007-11-24-advancing-rails-ein-workshop-mit-david-a-black/" rel="bookmark" class="crp_title">Advancing Rails &#8211; Ein Workshop mit David A. Black</a></li><li><a href="http://www.christophbuente.de/2007-11-25-ruby-on-rails-auf-mac-os-x-5-minuten-kurzanleitung/" rel="bookmark" class="crp_title">Ruby on Rails auf Mac OS X &#8211; 5 Minuten Kurzanleitung</a></li><li><a href="http://www.christophbuente.de/2007-11-17-canoo-webtest-web-anwendungen-automatisch-testen/" rel="bookmark" class="crp_title">canoo webtest &#8211; Web-Anwendungen automatisch testen</a></li><li><a href="http://www.christophbuente.de/2007-10-05-frei-nehmen-um-zu-lernen/" rel="bookmark" class="crp_title">Rails tutorial &#8211;  Eine Woche lang Agile Webentwicklung</a></li><li><a href="http://www.christophbuente.de/2007-06-19-performance-tests/" rel="bookmark" class="crp_title">Performance Tests</a></li></ul></div>]]></content:encoded>
			<wfw:commentRss>http://www.christophbuente.de/2009-05-16-remarkable-rails-anwendungen-automatisch-testen/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ruby on Rails auf Mac OS X &#8211; 5 Minuten Kurzanleitung</title>
		<link>http://www.christophbuente.de/2007-11-25-ruby-on-rails-auf-mac-os-x-5-minuten-kurzanleitung/</link>
		<comments>http://www.christophbuente.de/2007-11-25-ruby-on-rails-auf-mac-os-x-5-minuten-kurzanleitung/#comments</comments>
		<pubDate>Sun, 25 Nov 2007 13:33:25 +0000</pubDate>
		<dc:creator>Christoph Bünte</dc:creator>
				<category><![CDATA[Ruby on Rails]]></category>
		<category><![CDATA[anleitung]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[kurzanleitung]]></category>
		<category><![CDATA[locomotive]]></category>
		<category><![CDATA[mac os x]]></category>
		<category><![CDATA[mac user]]></category>
		<category><![CDATA[os x]]></category>
		<category><![CDATA[software development]]></category>
		<category><![CDATA[Software Entwicklung]]></category>
		<category><![CDATA[tutorium]]></category>
		<category><![CDATA[web development]]></category>
		<category><![CDATA[Web Entwicklung]]></category>

		<guid isPermaLink="false">http://www.christophbuente.de/2007-11-25-ruby-on-rails-auf-mac-os-x-5-minuten-kurzanleitung/</guid>
		<description><![CDATA[Ruby on Rails isst in aller Munde, wenn es um Webentwicklung geht. Ich werde in Zukunft eine Reihe von Artikeln veröffentlichen, die etwas tiefer in die Materie eindringen. Dazu ist es aber nötig, dass jeder Leser weiss, wie man Ruby on Rails auf seinem Rechner zum laufen bekommt und ein Projekt erzeugt. Aus diesem Grund [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://rubyonrails.com/" title="Webentwicklung, die nicht weh tut">Ruby on Rails</a> isst in aller Munde, wenn es um Webentwicklung geht. Ich werde in Zukunft eine Reihe von Artikeln veröffentlichen, die etwas tiefer in die Materie eindringen. Dazu ist es aber nötig, dass jeder Leser weiss, wie man Ruby on Rails auf seinem Rechner zum laufen bekommt und ein Projekt erzeugt. Aus diesem Grund hier eine 5 Minuten Kurzanleitung. Als Mac User werde speziell auf das Betriebsystem <a href="http://www.apple.com/de/macosx/">Mac OS X</a> eingehen.</p>
<p><span id="more-22"></span></p>
<p>Um mit Rails auf dem Mac zu beginnen, gibt es zwei Möglichkeiten:</p>
<ol>
<li> 		<a href="http://hivelogic.com/narrative/articles/ruby-rails-mongrel-mysql-osx">Kompilieren und installieren aller benötigten Komponenten</a></li>
<li> 		Benutzen einer Applikation, die schon alles mitbringt.</li>
</ol>
<p>Getreu dem Motto dieses Artikels, empfehle ich den schnellen, einfachen Weg <img src='http://www.christophbuente.de/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  <a href="http://locomotive.raaum.org/" title="Ryan Rauum">Ryan Rauum</a> stellt auf seiner Website eine Cocoa Anwendung zur Verfügung, die bereits alle Komponenten &#8211; bis auf die Datenbank &#8211; in einer Anwendung bündelt. Die Installation ist so einfach, wie bei jeder anderen Anwendung.</p>
<ul>
<li> 		<a href="http://locomotive.raaum.org" title="Locomotive herunterladen">Herunterladen</a></li>
<li> 		DMG Datei doppelt anklicken</li>
<li> 		Locomotive Symbol in das Programmverzeichnis ziehen</li>
</ul>
<p>Als Datenbank empfehle ich für die ersten Schritte <a href="http://www.mysql.com">MySQL</a>. Über den Produktiveinsatz von MySQL mag man streiten, aber um einfach mal anzufangen reicht MySQL völlig aus. Die Dateien für sehr viele Betriebsysteme stehen auf der <a href="http://dev.mysql.com/downloads/mysql/5.1.html">download Seite</a> bereit. Die Installation besteht eigentlich nur noch aus dem entpacken des tar.gz Archivs und starten der darin enthaltenen .pkg Datei. Eine <a href="http://dev.mysql.com/doc/refman/5.1/de/mac-os-x-installation.html">Anleitung</a> hat MySQL auch online gestellt.</p>
<p>Nachdem die Datenbank nun läuft ist es Zeit Locomotive zu starten. In der Applikation kann nun ein beliebiges Projekt erstellt werden (Apfel + N). Dazu gibt man den Namen und Pfad an, in dem das neue Projekt erstellt werden soll. Wer glücklicher Besitzer einer <a href="http://macromates.com/">Textmate</a> Lizens ist, klickt rechts auf das erstellt Projekt im Locomotive Fenster und wählt: &#8220;Edit in Textmate&#8221;. Es geht aber auch jeder andere Editor, um die wenigen Schritte zum laufenden Projekt zu gehen.</p>
<p>Die Datei <code>config/database.yml</code> im Projektverzeichnis enthält die Angaben, um Rails mit der Datenbank kommunizieren zu lassen. Hier sind in der bei der Verwendung von MySQL lediglich die Datenbanknamen für development, test und production anzugeben. Bei Bedarf kann hier auch der Benutzer, Passwort und Host bzw. Socket angepasst werden. Der schnellste Weg zu den drei Datenbanken ist mit Hilfe des Terminals:</p>
<pre lang="bash">mysql -uUser -pPasswort</pre>
<p>In der geöffneten mysql shell sind die drei create Anweisungen nötig</p>
<pre lang="sql">
create database projektname_development;
create database projektname_test;
create database projektname_production;</pre>
<p>So, das war es eigentlich schon. Nachdem mit Hilfe von Locomotive der Server für das Projekt gestartet wurde, sollte man im Browser unter der Adresse: <code>http://localhost:3000</code> eine Erfolgsmeldung sehen:</p>
<p><em>Welcome aboard. You’re riding the Rails!</em></p>
<div id="crp_related"><h3>Ähnliche Beiträge:</h3><ul><li><a href="http://www.christophbuente.de/2008-07-30-gepatchte-mysql-version-nuetzliche-features-schluesselfertig-eingebaut/" rel="bookmark" class="crp_title">Gepatchte MySQL Version &#8211; nützliche Features schlüsselfertig eingebaut</a></li><li><a href="http://www.christophbuente.de/2008-07-01-mysql-myisam-index-oder-nicht/" rel="bookmark" class="crp_title">MySQL MyISAM &#8211; Index oder nicht?</a></li><li><a href="http://www.christophbuente.de/2010-07-20-rails-hosting-bei-rocket-rentals-auch-mit-staging-umgebung/" rel="bookmark" class="crp_title">Rails Hosting bei Rocket Rentals &#8211; auch mit Staging Umgebung</a></li><li><a href="http://www.christophbuente.de/2007-11-24-advancing-rails-ein-workshop-mit-david-a-black/" rel="bookmark" class="crp_title">Advancing Rails &#8211; Ein Workshop mit David A. Black</a></li><li><a href="http://www.christophbuente.de/2007-10-05-frei-nehmen-um-zu-lernen/" rel="bookmark" class="crp_title">Rails tutorial &#8211;  Eine Woche lang Agile Webentwicklung</a></li></ul></div>]]></content:encoded>
			<wfw:commentRss>http://www.christophbuente.de/2007-11-25-ruby-on-rails-auf-mac-os-x-5-minuten-kurzanleitung/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Advancing Rails &#8211; Ein Workshop mit David A. Black</title>
		<link>http://www.christophbuente.de/2007-11-24-advancing-rails-ein-workshop-mit-david-a-black/</link>
		<comments>http://www.christophbuente.de/2007-11-24-advancing-rails-ein-workshop-mit-david-a-black/#comments</comments>
		<pubDate>Sat, 24 Nov 2007 07:49:40 +0000</pubDate>
		<dc:creator>Christoph Bünte</dc:creator>
				<category><![CDATA[Ruby on Rails]]></category>
		<category><![CDATA[Software Entwicklung]]></category>
		<category><![CDATA[david black]]></category>
		<category><![CDATA[railsschulung]]></category>
		<category><![CDATA[selenium]]></category>
		<category><![CDATA[Testing]]></category>
		<category><![CDATA[Web Entwicklung]]></category>

		<guid isPermaLink="false">http://www.christophbuente.de/2007-11-24-advancing-rails-ein-workshop-mit-david-a-black/</guid>
		<description><![CDATA[&#8220;Wer rastet, der rostet.&#8221; &#8211; So geht es auch Software-Entwicklern. Wer sich nicht ständig nach neuem umschaut und den imaginären Werkzeugkasten mit neuen Tools füllt, wird irgendwann selbst zum alten Eisen gehören. Deswegen habe ich schon vor einiger Zeit angefangen, Ruby on Rails in meine Repertoire aufzunehmen. Diese Woche habe ich in einem 4 Tage [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.flickr.com/photos/berlinchrizzle/2056227725/" title="IMG_5150-2 by chrizzle my nizzle, on Flickr"><img src="http://farm3.static.flickr.com/2350/2056227725_6a2bff9597_o.jpg" style="padding-right: 10px; height: 180px; float: left" alt="IMG_5150-2" /></a></p>
<p><i>&#8220;Wer rastet, der rostet.&#8221;</i> &#8211; So geht es auch Software-Entwicklern. Wer sich nicht ständig nach neuem umschaut und den imaginären Werkzeugkasten mit neuen Tools füllt, wird irgendwann selbst zum alten Eisen gehören. Deswegen habe ich schon vor einiger Zeit angefangen, Ruby on Rails in meine Repertoire aufzunehmen. Diese Woche habe ich in einem <a href="http://dablog.rubypal.com/2007/10/19/advancing-with-rails-training-in-berlin-nov-19-22">4 Tage Workshop</a> mein Wissen über Ruby und Rails weiter ausbauen können.</p>
<p><span id="more-21"></span></p>
<p>[ad#vert-banner]</p>
<p><a href="http://dablog.rubypal.com/">David A. Black</a>, Autor des Buches <a href="http://rubypal.org/ruby_for_rails">&#8220;Ruby for Rails&#8221;</a> ist für diesen Workshop aus New Jersey, USA angereist. Neben einem ganzen Tag für ActiveRecord und REST, wurden auch Themen wie &#8220;routing, testing, caching, deploy, plugins, rjs und javascript behandelt. Das Ganze war gespickt mit hunderten von ad hoc Beispielen, die David in seiner ganz eigenen Art in die Konsole oder den irb hackt.</p>
<p>Derartig tiefgreifende Kenntnis über eine bestimmte Thematik ist mir bisher noch nicht begegnet. Klar, arbeit man hier und da mit Leuten zusammen, die deutlich fitter sind als man selbst. Doch David &#8220;lebt&#8221; Ruby seit Jahren.</p>
<p>Um hier nicht nur meine Freude für Ruby und Rails zum Ausdruck zu bringen, sondern vielleicht auch ein nützliches Detail zu liefern, möchte ich das <a href="http://www.openqa.org/selenium/">Test Framework Selenium</a> erwähnen. Damit ist es möglich über die hoffentlich bereits geschriebenen Unit-, Functional- und Integrationtests hinaus, die Anwendung in einem echten Browser zu testen. Damit kann der Kunde sehr schnell sehen, was geht und was nicht. Und was noch viel wichtiger ist: wie es aussieht in verschiedenen Browsern aussieht.</p>
<p>Die Installation ist schnell und einfach. Im Hauptverzeichnis des Rails Projektes installiert wird das Plugin mit Hilfe des folgenden Kommandozeilen Befehls installiert:</p>
<pre lang="bash"> ruby script/plugin install selenium</pre>
<p>Anschließend generiert man eine Testdatei im Ordner <code>test/selenium</code> mit folgendem Befehl:</p>
<pre lang="bash"> ruby script/generate selenium login.rse</pre>
<p>Der generierte Testfall muss nun noch editiert werden, um die Applikation sinnvoll zu testen. Dabei können sämtliche Benutzerinteraktionen in lesbarer Form geskriptet werden. Die <a href="http://release.openqa.org/selenium-core/0.8.0/reference.html">Kommandoreferenz</a> findet man hier. Sollte die Anwendung bisher noch nicht im Testmodus verwendet worden sein, ist es nötig, die Testdatenbank auf den neuesten Stand zu bringen:</p>
<pre lang="bash"> rake db:migrate RAILS_ENV=test</pre>
<p>Damit die Tests auch durchführbar sind, muss der Server im Testmodus gestartet werden:</p>
<pre lang="bash"> ruby script/server -e test</pre>
<p>Ruft man jetzt die Rails Anwendung in einem beliebigen Browser auf (http://localhost:3000/selenium) sieht man das Admininterface von Selenium. Hier lässt sich einstellen, welche Tests laufen sollen. Darüber hinaus lassen sich noch die Geschwindigkeit und Highlighting variieren. Ein Klick auf den &#8220;Play-Button&#8221; im oberen rechten Fenster lässt die Show beginnen. Eine <a href="http://www.openqa.org/selenium-core/usage.html">ausführliche Anleitung</a> zur Benutzung des Interface findet man ebenfalls auf der selenium Webseite. Nach belieben können weitere Tests generiert werden und erscheinen dann automatisch im linken Fenster neben dem bereits erstellen login test.</p>
<p>Abschließend möchte ich <a href="http://www.railsschulung.de/" title="railsschulungen in Berlin">Benjamin und Mathias</a> danken, dass sie David nach Berlin gebracht haben. Es war spitze!</p>
<div id="crp_related"><h3>Ähnliche Beiträge:</h3><ul><li><a href="http://www.christophbuente.de/2007-11-27-kostenloses-ruby-on-rails-buch-nur-noch-4-tage/" rel="bookmark" class="crp_title">Kostenloses Ruby on Rails Buch &#8211;  Nur noch 4 Tage</a></li><li><a href="http://www.christophbuente.de/2009-05-16-remarkable-rails-anwendungen-automatisch-testen/" rel="bookmark" class="crp_title">Remarkable &#8211; Rails Anwendungen automatisch testen</a></li><li><a href="http://www.christophbuente.de/2007-11-25-ruby-on-rails-auf-mac-os-x-5-minuten-kurzanleitung/" rel="bookmark" class="crp_title">Ruby on Rails auf Mac OS X &#8211; 5 Minuten Kurzanleitung</a></li><li><a href="http://www.christophbuente.de/2007-12-31-2008/" rel="bookmark" class="crp_title">2008</a></li><li><a href="http://www.christophbuente.de/2007-10-05-frei-nehmen-um-zu-lernen/" rel="bookmark" class="crp_title">Rails tutorial &#8211;  Eine Woche lang Agile Webentwicklung</a></li></ul></div>]]></content:encoded>
			<wfw:commentRss>http://www.christophbuente.de/2007-11-24-advancing-rails-ein-workshop-mit-david-a-black/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Rails tutorial &#8211;  Eine Woche lang Agile Webentwicklung</title>
		<link>http://www.christophbuente.de/2007-10-05-frei-nehmen-um-zu-lernen/</link>
		<comments>http://www.christophbuente.de/2007-10-05-frei-nehmen-um-zu-lernen/#comments</comments>
		<pubDate>Fri, 05 Oct 2007 06:07:39 +0000</pubDate>
		<dc:creator>Christoph Bünte</dc:creator>
				<category><![CDATA[Ruby on Rails]]></category>
		<category><![CDATA[agile web]]></category>
		<category><![CDATA[agile web entwicklung]]></category>
		<category><![CDATA[buchempfehlung]]></category>

		<guid isPermaLink="false">http://www.christophbuente.de/2007/10/05/frei-nehmen-um-zu-lernen/</guid>
		<description><![CDATA[Diese Woche war für mich persönlich eine der lehrreichsten seit langem. Klar lernt man bei der täglichen Arbeit hier und da neue Sachen, jedoch ist es nicht das lernen, was ich meine. Seit Dienstag habe ich mich mit meinem Rechner und dem Buch &#8220;Agile Web Development with Rails&#8221; bei einem Freund im Büro eingeschlossen, um [...]]]></description>
			<content:encoded><![CDATA[<p>Diese Woche war für mich persönlich eine der lehrreichsten seit langem. Klar lernt man bei der täglichen Arbeit hier und da neue Sachen, jedoch ist es nicht das lernen, was ich meine. Seit Dienstag habe ich mich  mit meinem Rechner und dem Buch &#8220;<a href="http://www.amazon.de/gp/redirect.html%3FASIN=0977616630%26tag=chribuensofte-21%26lcode=xm2%26cID=2025%26ccmID=165953%26location=/o/ASIN/0977616630%253FSubscriptionId=1YNZ339ZCHHAKYFSY702">Agile Web Development with Rails</a>&#8221; bei einem <a href="http://www.paperplanes.de/">Freund</a>  im Büro eingeschlossen, um mir die <a href="http://rubyonrails.com/">Ruby on Rails</a> Technologie mal näher anzusehen. Nach ca. 4 Jahren <a href="http://java.sun.com/">Java Entwicklung</a> ist ein Blick über den Tellerrand längst überfällig.</p>
<p><span id="more-14"></span></p>
<p>[ad#vert-banner]</p>
<p>Für mich als eingefleischten Java Entwickler ist die Syntax sicher die größte Umstellung beim erlernen einer neuen Programmiersprache. Doch Ruby und damit auch Rails macht es dem Entwickler durch gut lesbaren code sehr leicht, die Semantic des Codes zu verstehen. Dazu kommt, daß Rails dem Entwickler durch sorgfältig durchdachte Konventionen bereits viele Entscheidungen abnimmt. Wo kommt der Code für die Controller, die Tests hin, wo lege ich Bilder und statischen Inhalt ab, wie benenne ich Dateien und Datenbank Tabellen? All diese Fragen führen im Projektalltag durch Permutation zu einer riesigen Anzahl von Möglichkeiten, die ständig Entscheidungen verlangen. Und wo mehrere Entwickler zusammen arbeiten, fallen die Entscheidungen nicht immer gleich aus, was letztlich zur Entropie des Projektes beiträgt.</p>
<p>In dem genannten Buch werden anhand eines ca. 150 seitigen Tutorials alle Facetten des Rails Frameworks zumindest gestreift, und in mehreren anschließenden Kapiteln amüsant vertieft. In dem Tutorial wird das Leben eines Webentwicklers am Beispiel eines Webshops beschrieben. Kurze Iterationen und frühes Feedback vom Kunden unterstützen den agilen Entwicklungsprozess ebenso, wie kurzer, gut lesbarer Code, der sich schnell ändern und testen läßt. Von Langeweile, wie bei den üblichen Hello Word Tutorien ist hier keine Spur!</p>
<p>Besonders beeindruckend fand ich neben den bereits implementierten xml und string output Methoden die dynamisch erzeugbaren Finder methoden, um Objekte in der Datenbank anhand bestimmter Attribute zu finden. Kombiniert mit deklarierbaren Objekt Assoziationen ergeben sich daraus mächtige Werkzeuge, die in Java Projekten regelmäßig eine Diskussion und Implementierungsorgie auslösen. Das folgende Beispiel enthält eine zur Laufzeit dynamisch erzeugte Methode, die einfach zu lesen ist und keines Kommentares bedarf.</p>
<p><code>users = User.find_all_by_firstname_and_lastname ("Dave", "Thomas")</code></p>
<p>Mit diesen ersten Eindrücken hinterlasse ich den geneigten Leser und möchte jeden animieren, sich dieses wertvolle Buch zu kaufen. Ruby on Rails bringt wieder Spaß in die Webentwicklung.</p>
<div id="crp_related"><h3>Ähnliche Beiträge:</h3><ul><li><a href="http://www.christophbuente.de/2007-11-27-kostenloses-ruby-on-rails-buch-nur-noch-4-tage/" rel="bookmark" class="crp_title">Kostenloses Ruby on Rails Buch &#8211;  Nur noch 4 Tage</a></li><li><a href="http://www.christophbuente.de/2007-11-25-ruby-on-rails-auf-mac-os-x-5-minuten-kurzanleitung/" rel="bookmark" class="crp_title">Ruby on Rails auf Mac OS X &#8211; 5 Minuten Kurzanleitung</a></li><li><a href="http://www.christophbuente.de/2007-08-05-objekte-und-beziehungen/" rel="bookmark" class="crp_title">Objekte und Beziehungen</a></li><li><a href="http://www.christophbuente.de/2007-11-24-advancing-rails-ein-workshop-mit-david-a-black/" rel="bookmark" class="crp_title">Advancing Rails &#8211; Ein Workshop mit David A. Black</a></li><li><a href="http://www.christophbuente.de/2009-05-16-remarkable-rails-anwendungen-automatisch-testen/" rel="bookmark" class="crp_title">Remarkable &#8211; Rails Anwendungen automatisch testen</a></li></ul></div>]]></content:encoded>
			<wfw:commentRss>http://www.christophbuente.de/2007-10-05-frei-nehmen-um-zu-lernen/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Objekte und Beziehungen</title>
		<link>http://www.christophbuente.de/2007-08-05-objekte-und-beziehungen/</link>
		<comments>http://www.christophbuente.de/2007-08-05-objekte-und-beziehungen/#comments</comments>
		<pubDate>Sun, 05 Aug 2007 10:05:20 +0000</pubDate>
		<dc:creator>Christoph Bünte</dc:creator>
				<category><![CDATA[Datenbanken]]></category>
		<category><![CDATA[Ruby on Rails]]></category>
		<category><![CDATA[anzahl der kinder]]></category>
		<category><![CDATA[counter_cache]]></category>
		<category><![CDATA[parent id]]></category>
		<category><![CDATA[sql]]></category>

		<guid isPermaLink="false">http://www.christophbuente.de/2007/08/05/objekte-und-beziehungen/</guid>
		<description><![CDATA[Wie im täglichen Leben stehen auch bei der programmatischen Nachbildung der Wirklichkeit Objekte oft in einer bestimmten Beziehung zu einander. Dabei unterscheidet man zwischen 1:1, 1:n und m:n Beziehungen. Neulich wollte ich in einer kleinen Rails Web-Applikation (siehe aktuelle Literatur) eine Ansicht einer 1:n Beziehung zweier Objekte in Listenform erstellen. Die Anforderung war allerdings, die [...]]]></description>
			<content:encoded><![CDATA[<p>Wie im täglichen Leben stehen auch bei der programmatischen Nachbildung der Wirklichkeit Objekte oft in einer bestimmten Beziehung zu einander. Dabei unterscheidet man zwischen 1:1,  1:n und m:n Beziehungen.</p>
<p>Neulich wollte ich in einer kleinen Rails Web-Applikation (siehe aktuelle Literatur) eine Ansicht einer 1:n Beziehung zweier Objekte in Listenform erstellen. Die Anforderung war allerdings, die Liste nach der Anzahl der Kinder zu sortieren und dabei die Objekte zuerst anzuzeigen, die keine Kinder haben.</p>
<p><span id="more-11"></span></p>
<p>[ad#vert-banner]</p>
<p>Damit die Ergebnismenge des SELECT Statements auch die Eltern Objekte enthält, die keine Kinder besitzen, muss ein LEFT JOIN verwendet werden. Grundsätzlich ist das zwar etwas mehr Aufwand für die Datenbank, aber dennoch schaffbar, ohne eine Ewigkeit warten zu müssen. Mit Hilfe von Indizierungen lässt sich die ganze Sache auch hinreichend beschleunigen. Das folgende SQL Statement erfüllt diese erste Anforderung:</p>
<pre lang="sql">
SELECT p.name, c.name
FROM parents AS p
LEFT JOIN children AS c
ON p.id=c.parent_id</pre>
<p>Allerdings fehlt hier die Sortierung. Das zweite Problem ist, dass das Feld <code>c.name</code> für alle kinderlosen Eltern NULL ist, und somit nicht gezählt werden kann. Folgendes Statement behebt zwar das Problem, aber die Ausführung braucht bei großen Tabellen Jahre.</p>
<pre lang="sql">
SELECT IF(c.id IS NULL,0,COUNT(*)) AS kids, p.name
FROM parents AS p
LEFT JOIN children AS c ON p.id=c.parent_id
ORDER BY kids
GROUP BY p.id</pre>
<p>Die lange Ausführungsdauer hat vor allem einen Grund: Die Sortierung geschieht auf einer Spalte, die effektiv nicht existiert, sondern erst zur Laufzeit mit Hilfe der Count Funktion erzeugt wird. Das heißt es muss erst ein kompletter Join über beide Tabellen durchgeführt werden, ehe eine Sortierung stattfinden kann. Auch eine Limitierung der Ergebnisliste mit Hilfe von LIMIT ändert daran nichts, denn die würde erst nach der Sortierung durchgeführt.</p>
<p>Um diese lange Wartezeiten zu vermeiden, habe ich mir folgendes überlegt: Man baut in die Tabelle der Elternklasse eine Spalte ein, die die Anzahl der Kinder speichert. Nun muss &#8220;nur noch&#8221; beim hinzufügen und löschen eines Kindes diese Spalte gepflegt werden. Das heißt, meine Applikation ist für die Datenintegrität zuständig.</p>
<p>Zurück zu Rails, denn da ist dieses Funktionalität bereits an Board. Getreu dem Motto &#8220;Konvention über Konfiguration&#8221;, erzeugt man lediglich die Spalte in der Tabelle der Elternklasse. Diese trägt den sprechenden Namen &lt;kindertabelle&gt;_count also in diesem falls children_count. In der Kinderklasse wird nun noch deklariert, dass der Zähler automatisch aktualisiert wird.</p>
<pre lang="ruby">
class Child < ActiveRecord::Base
  belongs_to :parent, :counter_cache => true
end</pre>
<p>Und siehe da, nun lässt sich eine normaler Finder verwenden, um den View aufzubauen. Komplett ohne JOIN!</p>
<pre lang="ruby">@parents = Parent.find(
  :all,
  :limit => 20,
  <img src='http://www.christophbuente.de/wp-includes/images/smilies/icon_surprised.gif' alt=':o' class='wp-smiley' /> ffset => @parent_pages.current.to_sql[1],
  <img src='http://www.christophbuente.de/wp-includes/images/smilies/icon_surprised.gif' alt=':o' class='wp-smiley' /> rder => "children_count ASC, parent ASC")</pre>
<p>Da jetzt nur noch real existierende Spalten für die Sortierung verwendet werden und eine effektive Limitierung der Ergebnismenge möglich ist, dauert die Anfrage nur noch wenige ms.</p>
<p>Thx Rails!</p>
<div id="crp_related"><h3>Ähnliche Beiträge:</h3><ul><li><a href="http://www.christophbuente.de/2007-10-05-frei-nehmen-um-zu-lernen/" rel="bookmark" class="crp_title">Rails tutorial &#8211;  Eine Woche lang Agile Webentwicklung</a></li><li><a href="http://www.christophbuente.de/2008-07-01-mysql-myisam-index-oder-nicht/" rel="bookmark" class="crp_title">MySQL MyISAM &#8211; Index oder nicht?</a></li><li><a href="http://www.christophbuente.de/2007-06-19-performance-tests/" rel="bookmark" class="crp_title">Performance Tests</a></li><li><a href="http://www.christophbuente.de/2007-11-24-advancing-rails-ein-workshop-mit-david-a-black/" rel="bookmark" class="crp_title">Advancing Rails &#8211; Ein Workshop mit David A. Black</a></li><li><a href="http://www.christophbuente.de/2008-01-24-stripes-framework-tests-fur-actionbeans-im-wizard-modus/" rel="bookmark" class="crp_title">Stripes Framework &#8211; Tests für ActionBeans im Wizard Modus</a></li></ul></div>]]></content:encoded>
			<wfw:commentRss>http://www.christophbuente.de/2007-08-05-objekte-und-beziehungen/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

<!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Minified using memcached (Feed is rejected)
Page Caching using memcached
Database Caching 14/50 queries in 0.073 seconds using memcached
Object Caching 1673/1756 objects using memcached

Served from: www.christophbuente.de @ 2012-02-08 09:52:58 -->
