Showing posts with label rails. Show all posts
Showing posts with label rails. Show all posts

Wednesday, August 20, 2008

Found a Bug in Rails 2.1... kinda

Yesterday I've encountered some strange behavior in Rails 2.1. When I called build on an association that was empty (i.e. customer.orders.build) and then passed that association as a collection to a partial, nothing got displayed. When I called length or each {} on that association right after the call to build, however, it worked. So I sort of needed to "commit" the build call by calling length right after.
I posted it to the Ruby On Rails Core group and it turned out that it was indeed a bug. It had been fixed in edge already, though.
So if you're not using edge, but the actual Rails 2.1 release, make sure to call length (i.e. customer.orders.length) after you call build on an empty association until the fixed version gets released.

Tuesday, July 15, 2008

Check If a Remote File or Directory Exists with Capistrano

I have a Rails app that can have custom logos for different deployments. I wanted to make it easy and simply drop the custom images into a shared/images directory and have Capistrano copy them to current/public/images but only when the shared/images directory exists. Naively I tried this:


if File.directory? "#{shared_path}/images"
run "cp #{shared_path}/images/* #{release_path}/public/images/"
end

Haha, cute. This does not work, since it checks for the LOCAL file, not for the file on the remote machine. Others had a similar problem.
So what's the solution? For me it was to realize that there are other languages besides Ruby to do the job, namely shell scripting. So to conditionally copy files only if a certain directory exists on the remote machine, use this one liner:

# if the shared/images directory exists, copy all images from there to the current/public/images directory
# to replace logos and stuff like that
run "if [[ -d #{shared_path}/images ]]; then cp #{shared_path}/images/* #{release_path}/public/images/; fi"

Enjoy!

Run Your Rails Application Offline Without Slingshot

I just read about a cool project over at the Google Code Blog. Two graduates from NYU have created a Rails plugin called Gears on Rails or acts_as_local. It uses Google Gears for local data storage so you can run your Rails application offline. From the website:

Gears on Rails helps developers to write fully offline functionnal web applications based on Gears without learning a bit of Gears.


That sounds very cool. The website has a demo so you can dive into the code right away. This might be a nice alternative to Slingshot, although Slingshot also hides the Ruby requirements from the user and packages everything up nicely, something Gears On Rails doesn't do. But it shouldn't be too hard to implement a Slingshot clone based on Gears On Rails. We'll see.

Wednesday, July 2, 2008

Rails 2.1 Killed My MySql Foreign Keys


I'm porting a big Rails 1.2.x application to Rails 2.1 at the moment. Everything went smoothly so far, I used the rake deprecated task and watched out for gotchas, and replaced Rails 1.2.x pagination with will_paginate.
When I tried to run my test suite, though, it threw up all over my terminal:


Mysql::Error: #HY000Can't create table './coresales_test/#sql-1702c_b.frm' (errno: 150): ALTER TABLE agents ADD CONSTRAINT agents_ibfk_1 FOREIGN KEY (location_id) REFERENCES locations (id)

It took me a bit to find the solution for this, but alas! I eventually did. To make a long story short: Rails 2.1 doesn't handle integer columns without a :limit attribute correctly by assuming a default limit of 11 and then turning that - not into int(11) - but into bigint(11). Foreign keys have to be of the same data type, though. So MySql rightly complains about it.
The solution? Either use edge rails or use the monkey patch suggested in this extensive blog post about the problem.
This was really quite annoying, but I'm glad that there are nice people out there providing patches and nice write-ups about such problems.

If this was useful for you, please take a minute and recommend me:
Recommend Me
Thank you!

Thursday, June 19, 2008

Using Rails gems:build Rake Task with Capistrano

I use acts_as_ferret in my Rails app which depends on the ferret gem. With Rails 2.1 you can define gem dependencies right in your environment.rb file. That's pretty neat. What if your gem needs native extensions to be built? Also easy, just run

rake gems:build

Of course you'd also like these extensions to be built on your production machine when you deploy with Capistrano. I'm sure there are more elegant ways to do this, but this works for me. Just add this to your deploy.rb file:

task :after_update_code, :roles => :app do
if ENV['build_gems'] and ENV['build_gems'] == '1'
run "rake -f #{release_path}/Rakefile gems:build"
end
end

This way you can pass an environment variable to tell Capistrano if you want native gem extensions to be built or not. If you do, call this:
build_gems=1 cap deploy

...and if you don't just call
cap deploy
.

I always love to learn about more elegant solutions, so please comment if you know one.

If this was useful for you, please take a minute and recommend me:
Recommend Me
Thank you!

Unit Testing with acts_as_ferret


I'm using acts_as_ferret for full text search in a Rails app I'm building. It works great and of course I want to unit test the full text search in my models. So I added an extremely simple test (I have two fixtures that have the matching string "bla" in on of their indexed fields):


def test_find_by_contents
assert_equal 2, MyModel.find_by_contents('bla').total_hits
end

This is great, except for one small problem: it almost always fails! The total_hits are sometimes 1, sometimes 0 and hardly ever 2. Why? Because the data from the fixtures is rebuilt before every test case so ferret can't keep it's index up to date quickly enough.
A very crude but simple solution is to rebuild the index before ferret-related tests:

def test_find_by_contents
MyModel.rebuild_index
assert_equal 2, MyModel.find_by_contents('bla').total_hits
end

Now it works as expected. This will affect performance, though. So if you have a huge test suite, you might want to consider using the preload fixtures plugin from ELC Technologies. I haven't tried this, but it most likely will also eliminate the need to rebuild the index before ferret related tests since the fixtures are not constantly dumped and rebuilt.

If this was useful for you, please take a minute and recommend me:
Recommend Me
Thank you!

Thursday, May 29, 2008

Set a Date Attribute from date_select Without Mass Assignment in Ruby On Rails

This has been talked about a million times, but I just ran into this problem again and want to share the solution:
You have a date_select helper in your Rails view and you want to assign the selected date to your model. With mass assignment that's not a problem, but when you try this:


@something.my_date = params[:something][:my_date]

You will be disappointed and there will be wailing and gnashing of teeth. Why? Because date_select creates 3 form components and 3 corresponding values in the form and in the params[:something] hash, namely

params[:something][:my_date(1i)]
params[:something][:my_date(2i)]
params[:something][:my_date(3i)]

These represent the year, the month and the day (Duh!).
When you use @something.attributes= to mass assign this, ActiveRecord takes care of creating a date object from these three values (see attributes=, assign_multiparameter_attributes, extract_callstack_for_multiparameter_attributes, and execute_callstack_for_multiparameter_attributes). Sometimes you might not want to mass assign, though (security comes to mind).
So what are you to do? Maybe putting this code (inspired by this code) in your application.rb might help:

private

def convert_date(hash, date_symbol_or_string)
attribute = date_symbol_or_string.to_s
return Date.new(hash[attribute + '(1i)'].to_i, hash[attribute + '(2i)'].to_i, hash[attribute + '(3i)'].to_i)
end

Now you can assign dates from date_select like this:

@something.my_date = convert_date(params[:something], :my_date)

Please comment if you have a better or more elegant solution!

If this was useful for you, please take a minute and recommend me:
Recommend Me
Thank you!

Tuesday, May 27, 2008

Rails Time Travel: Manipulating Time.now for Tests

Can we go anywhere we want at any time?
You can do anything you want.


Do you have code in your Ruby on Rails models that depends on the current date and time? I do. And I want to test it to make sure it works right. In my case a certain date is only valid if it is in the current month or in the previous month but only if it's not the 11th day of the month yet. If today were the 10th of May - for example - a date in April would be valid. If today were the 11th of May, a date in April wouldn't be valid anymore, though.
Just testing this piece of code if the day the tests are being run happens to be below the 11th day of the month is not a solution, of course. So I googled a bit and found this wonderful piece of code.

These are the steps to get your Rails Time Machine (tm) up and running:
  1. Copy the above code to a file and save it as test/time_helper.rb
  2. Require it in your test:
    require File.dirname(__FILE__) + '/../time_helper'
  3. Either set the time for all the tests in the file:

    def setup
    pretend_now_is(Time.local(2007, 8, 1)) # position *all* tests back in time!
    end

    def teardown
    Time.reset # jump back to the present
    end

    or just do some time travel for a code block:

    def test_decades
    pretend_now_is(Time.local(1960)) do
    assert_equal(1960, Time.now.year)
    end
    pretend_now_is(Time.local(1970)) do
    assert_equal(1970, Time.now.year)
    end
    # ...
    end
    (These code samples come from here. Thank you!)
  4. Find a street where your De Lorean can reach 88 mph and run your time traveling tests!
Please give my regards to Bill and Ted if you meet them.

If this was useful for you, please take a minute and recommend me:
Recommend Me
Thank you!

Monday, May 5, 2008

Setting up attachment_fu for Rails with ImageScience on a Mac


Who doesn't need file uploads in their Rails app? Lots of people, but I'm unfortunately not one of them. No need to reinvent the wheel, though since there's a spiffy plugin called attachment_fu by Rails core contributor Rick Olsen aka techno weenie.
How to set this sucker up on Mac OS? Easy:

Update:Digging through the source of the attachment_fu plugin I found something very cool that's not mentioned in the README: it comes with a CoreImage image processor. So if you use a current version of Mac OS X you can skip straight to step 7. Attachment_fu will find CoreImage on it's own. If not, just supply :core_image as the :processor parameter for has_attachment.


  1. Install MacPorts by following the instructions. A .profile should be created by the install script. It didn't feel like doing that on my system, so I created a .profile file in my home directory with this contents:

    export PATH=/opt/local/bin:/opt/local/sbin:$PATH
    export MANPATH=/opt/local/share/man:$MANPATH


  2. Restart Terminal.app


  3. Update the MacPorts ports:

    sudo port selfupdate


  4. Install FreeImage:

    sudo port install freeimage


  5. Install RubyInline:

    sudo gem install RubyInline


  6. Install the ImageScience gem:

    sudo gem install -y image_science


  7. Finally install the attachment_fu plugin (run this in your Rails project directory):

    script/plugin install http://svn.techno-weenie.net/projects/plugins/attachment_fu/



That's it. Thanks to Mike Clark for his informative blog post.
What next? Read above mentioned informative blog post to learn how to use attachment_fu in your app or read this Advanced Rails Recipe (PDF) on the topic.

Q&A


Q: Why did you use attachment_fu and not one of the other file upload plugins?
A: Because (1) Rick Olsen knows what he is doing, (2) is a Rails core contributor and (3) has a proven record of great plugins. Oh, and because attachment_fu seems to (4) be actively maintained and (5) supports file system, database and even Amazon S3 data stores.

Q: Why did you choose FreeImage and ImageScience and not ImageMagick and RMagick or MiniMagick?
A: Especially RMagick has the reputation of being a leaking memory hog. I haven't tried it myself, but ImageScience and FreeImage seem to be a lean choice and they do a great job.

If this was useful for you, please take a minute and recommend me:
Recommend Me
Thank you!

Thursday, April 24, 2008

The Future for Rails Developers

engine yard logoI just listened to an interesting podcast interview with Tom Mornini, the CTO of Engine Yard. In it he talks a bit about what his company does and the challenges of scalable Rails deployment, but the bit I found especially interesting is what he had to say about Rails developers. He said that there is a huge demand for them and that new developers can't be taught quickly enough to fill that need. He says that it's going to be a multi year process to teach enough developers to satisfy the demand the market has for them.
I guess that puts us Rails developers in a cozy position :)

Wednesday, April 23, 2008

Schritt für Schritt Anleitung: Ruby On Rails Deployment mit Capistrano, Mongrel, Apache, Subversion und Dir

Note to English speaking readers: I've written this tutorial in German because there are a lot of good Rails deployment tutorials out there in English, but not so many in German. If enough people email me or comment and say they want this in English I might translate it ;-).

So, jetzt auf Deutsch: Du willst deine grossartige nagelneu programmierte Ruby On Rails Anwendung fuer die Welt (oder immerhin fuer deinem Kunden) nutzbar machen. Dann will ich dich nicht aufhalten und dir in 27 einfachen Schritten zeigen, wie es geht. Dann wollen wir mal...


  1. Log dich mit ssh in den Server ein, auf dem die Rails Applikation laufen soll.

  2. Wenn du dich nicht als root angemeldet hast, werde jetzt root (su -)

  3. Stell sicher, dass ein Editor wie vi richtig funktioniert. Wenn man von Mac OS X auf einen Linux Rechner geht kann es manchmal Probleme geben. Auf Debian Systemen schafft da oft

    apt-get install ncurses-term

    Abhilfe.

  4. Aktualisiere die verfuegbaren Pakete:

    apt-get update

  5. Installiere folgende Pakete:
    apt-get install mysql-server
    apt-get install ruby
    apt-get install ruby1.8-dev
    apt-get install rubygems
    apt-get install subversion
    apt-get install make
    apt-get install build-essential
    apt-get install curl
    apt-get install apache2
  6. Installiere folgende Ruby Gems:
    gem install --include-dependencies rails
    gem install --include-dependencies capistrano
    gem install --include-dependencies mongrel (jeweils die neuste ruby version nehmen)
    gem install --include-dependencies mongrel_cluster

  7. Gehe nochmal sicher, dass alles aktuell ist:

    gem update --system

    Wenn du irgendwo den Fehler

    /usr/bin/gem:23: uninitialized constant Gem::GemRunner (NameError)

    bekommst ist das damit zu loesen, folgende Zeile in /usr/bin/gem einzufuegen:

    require 'rubygems/gem_runner'

    Und um den Fehler

    undefined method `require_gem' for main:Object

    spaeter beim Deployment zu vermeiden solltest du nochmal

    gem install --remote rake

    ausfuehren. Wenn das nicht hilft, in /var/lib/gems/1.8/bin/rake

    require_gem 'rake', version

    in

    gem 'rake', version

    abaendern.

  8. Jetzt musst du die Datenbank einrichten. Wir nehmen hier MySQL und der Einfachheit halber nenne ich in dieser Anleitung die Datenbank, den Datenbank Benutzer und die Rails-Anwendung "springenwerk".

    Root Passwort setzen:

    mysqladmin -u root password ein_passwort_meiner_wahl

    (danach am besten die bash_history loeschen) Dann die Datenbank anlegen und die Berechtigung setzen:

    mysql -u root -p
    CREATE DATABASE springenwerk;
    GRANT ALL PRIVILEGES ON springenwerk.* TO 'springenwerk'@'localhost' IDENTIFIED BY 'ein_password_meiner_wahl' WITH GRANT OPTION;

    Die Angaben fuer die Produktions-Datenbank (Name, Username und Passwort) muessen den Angaben in der app/config/database.yml Datei der Rails Anwendung entsprechen.

    Jetzt kannst du den Mysql Client mit 'exit' verlassen.

  9. Die ausfuehrbaren Ruby Gems willst du jetzt natuerlich gerne in deinem Pfad haben. Also
    in der /etc/profile
    /var/lib/gems/1.8/bin
    an die PATH Variable haengen. Das kann man so machen:

    PATH=$PATH:/var/lib/gems/1.8/bin

    Du musst nur aufpassen, dass die das vor die Zeile "export PATH" schreibst.

  10. Dann die Aenderungen in der aktuellen Session nutzbar machen:

    source /etc/profile

    Wenn du dann

    rails -v

    ausfuehren kannst hat alles geklappt.

  11. Jetzt solltest du einen eigenen User fuer deine Rails Anwendung anlegen:

    useradd -m springenwerk

    und das Passwort setzten:

    passwd springenwerk

    Und ihn zu den sudoers packen:

    visudo

    und dann unten folgende Zeile hinzufuegen (natuerlich "springenwerk" wieder mit deinem Produktions-Usernamen ersetzen):

    springenwerk ALL=(ALL) ALL

  12. Da sich Capistrano per SSH einloggt aber auch ein gewisse Benutzerumgebung braucht (z.B. den PATH) musst du in die /etc/ssh/sshd_config folgende Zeilen einfuegen:
    # for capistrano
    PermitUserEnvironment yes
  13. Dann SSHD neu starten:

    /etc/init.d/ssh restart
  14. In /home/springenwerk/.ssh/environment (ggf. ".ssh" Verzeichnis und Datei anlegen) folgende Zeilen einfuegen:
    PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/var/lib/gems/1.8/bin
    RUBYOPT=rubygems
  15. Jetzt musst du auf dem CLIENT Capistrano und Mongrel Cluster installieren (ich gehe davon aus, dass Ruby und Rails schon installiert sind)
    sudo gem install capistrano
    sudo gem install capistrano-ext
    sudo gem install mongrel_cluster

    Ab Mac OS X Leopard ist capistrano schon dabei, aber stelle mit

    sudo gem update capistrano
    sicher, dass du mindestens Version 2.1 hast.

  16. Wechsle in dein Rails Projekt Verzeichnis:

    cd /Users/johannes/Code/springenwerk/trunk/springenwerk
  17. Jetzt erstellst du eine Konfigurationsdatei fuer den Mongrel Cluster:

    mongrel_rails cluster::configure -e production -p 8000 -a 127.0.0.1 -N 2 -c /home/springenwerk/springenwerk/current

    -p 8000 sagt, dass die Server ab Port 8000 lauschen, -N 2 sagt, dass es zwei Instanzen geben wird (also eine auf Port 8000, eine auf 8001) und mit -c gibt man das Verzeichnis an, wo auf dem PRODUKTIONSSERVER die Applikation liegen wird (in diesem Fall ein Unterverzeichnis, das so heisst wie die Applikation im Home-Verzeichnis des Users, den wir angelegt haben (welcher auch so heisst wie die Applikation) und mit dem Zusatz "current". Das musst da stehen, denn das
    ist ein Symlink, den Capistrano anlegt und der immer auf die aktuelle Version zeigt.

  18. Jetzt musst du dein Rails Projekt capistranofizieren ;-). Wechsle in dein Rails Projekt Verzeichnis:

    cd /Users/johannes/Code/springenwerk/trunk/springenwerk

    und fuehre capify aus:

    capify .

  19. Oeffne jetzt config/deploy.rb in deinem Editor und passe die Datei so an, dass sie so aussieht (mit deinen User- und Projektnamen und Passwoertern natuerlich):

    require 'mongrel_cluster/recipes'

    default_run_options[:pty] = true # to make sure password prompts are forwarded to you, the user

    set :application, "springenwerk"
    set :repository_url, "svn://DEIN_SVN_USER@DEIN_SVN_SERVER/springenwerk/trunk/springenwerk"

    if ENV['svn_prompt'] and ENV['svn_prompt'] == '1'
    set :svn_user, Proc.new { Capistrano::CLI.password_prompt('SVN User: ') }
    set :svn_password, Proc.new { Capistrano::CLI.password_prompt('SVN Password: ') }
    set :repository, Proc.new { "--username #{svn_user} --password #{svn_password} #{repository_url}" }
    else
    set :repository, repository_url
    end

    set :deploy_to, "/home/#{application}/#{application}" # defaults to "/u/apps/#{application}"
    set :deploy_via, "export"
    set :user, application # in our case, the user and the application have the same name.

    set :mongrel_conf, "#{current_path}/config/mongrel_cluster.yml"

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

    # Task to copy production db config after deployment
    task :after_update_code, :roles => :app do
    db_config = "#{shared_path}/config/database.yml.production"
    run "cp #{db_config} #{release_path}/config/database.yml"
    end

    Die Datei werde ich hier nicht gross erklaeren, dazu gibt es andere Stellen.

    Diese deploy.rb Datei hat aber eine kleine Besonderheit (Danke an Jonathan).
    Da Subversion natuerlich einen Benutzernamen und ein Passwort erwartet wird normalerweise empfohlen, einmal irgendwo auf dem Produktionsserver das Rails Projekt auszuchecken, damit die Credentials gecachet werden und Capistrano nicht mehr nach SVN Benutzernamen und Passwort fragt. Das koennen wir uns jetzt sparen.
    Wir koennen naemlich jetzt angeben, dass Capistrano uns beim ersten Mal einfach nach den Zugangsdaten fuer SVN fragt. Dazu gleich mehr.


  20. Jetzt kann Capistrano die Verzeichnisse auf dem Produktionsserver anlegen. Auf deinem CLIENT fuehre folgendes aus:

    cap deploy:setup
  21. Stelle die neuen Konfigurationsdateien unter Versionskontrolle und checke sie ein:

    svn add Capfile config/mongrel_cluster.yml config/deploy.rb
    svn ci -m "capistrano config"
  22. Du willst aus Sicherheitsgruenden deine Produktionsdatenbank Passwoerter nicht ins SVN einchecken. Deshalb solltest du eine Datei namens database.yml.production anlegen, die die
    Zugangsdaten fuer deine Produktionsdatenbank enthaelt. Unser "after_update_code" Task in deploy.rb erwartet diese Datei und kopiert sie dann ueber die ausgecheckte database.yml. Zum Beispiel koennte sie so aussehen:

    development:
    adapter: mysql
    database: springenwerk_development
    username: root
    password: root
    host: localhost
    socket: /Applications/MAMP/tmp/mysql/mysql.sock

    # Warning: The database defined as 'test' will be erased and
    # re-generated from your development database when you run 'rake'.
    # Do not set this db to the same as development or production.
    test:
    adapter: mysql
    database: springenwerk_test
    username: root
    password: root
    host: localhost

    production:
    adapter: mysql
    database: springenwerk
    username: springenwerk
    password: DEIN_PASSWORT
    host: localhost
    socket: /var/run/mysqld/mysqld.sock

    Diese packst du auf dem Produktionsserver in folgendes Verzeichnis:

    /home/springenwerk/springenwerk/shared/config
    Das config Verzeichnis musst du vorher anlegen.

  23. Jetzt kannst du mit Capistrano von deinem CLIENT ein Erst-Deployment (cold deployment) durchfuehren (in deinem Rails Projektverzeichnis)

    svn_prompt=1 cap deploy:cold
    "svn_prompt" ist einen Umgebungsvariable, die unserem deploy.rb Skript sagt, dass es nach den SVN Zugangsdaten fragen soll. Denke daran, dass wenn Capistrano dich nach dem Passwort fuer deinen Produktionsserver fragt das Passwort fuer den nicht-root User (in diesem Beispiel "springenwerk") fragt!

    Achte darauf, dass es keine Fehler gibt, am Ende sollte

    command finished
    stehen.

  24. Pruefe auf dem SERVER, ob die Mongrel Dienste laufen:

    curl -I http://127.0.0.1:8000
    Wenn Mongrel laeuft, sollte die Ausgabe ungefaehr so aussehen:

    HTTP/1.1 302 Moved Temporarily
    Connection: close
    Date: Wed, 06 Feb 2008 11:42:33 GMT
    Set-Cookie: _springenwerk_session_id=f4a9b408f36d0df7561fd778e46d2c62; path=/
    Status: 302 Found
    Location: http://127.0.0.1:8000/session/new
    Cache-Control: no-cache
    Server: Mongrel 1.1.3
    Content-Type: text/html; charset=utf-8
    Content-Length: 101

    Sehr gut. Jetzt musst du nur noch Apache als Loadbalancer einrichten. Ein Kinderspiel ;-)

  25. Ok, Apache. Bevor du die folgenden Sachen machst, ein kleiner Disclaimer: ich bin kein Apache-Config-Profi. Es kann gut sein, dass es elegantere Wege gibt, das gute Stueck zu konfigurieren. Alle Hinweise die zur Ergreifung des Taeters fuehren werden sehr geschaetzt.

    Ans Ende von /etc/apache2/apache2.conf folgendes anfuegen (im vi mit G ans Ende der Datei springen):

    <Proxy balancer://mongrel_cluster>
    BalancerMember http://127.0.0.1:8000
    BalancerMember http://127.0.0.1:8001
    </Proxy>
    Der Inhalt der /etc/apache2/sites-available/000-default Datei muss so aussehen (ich gehe in dem Beispiel davon aus, dass der Apache nur fuer deine Rails Anwendung benutzt wird):

    <VirtualHost *:80>
    ServerAdmin webmaster@localhost

    DocumentRoot /home/springenwerk/springenwerk/current/public
    <Directory /home/springenwerk/springenwerk/current/public>
    Options FollowSymLinks
    AllowOverride None
    Order allow,deny
    allow from all
    </Directory>

    RewriteEngine On

    RewriteLog /var/log/apache2/rewrite.log
    RewriteLogLevel 9

    RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f
    RewriteCond %{SCRIPT_FILENAME} !maintenance.html
    RewriteRule ^.*$ /system/maintenance.html [L]

    RewriteRule ^/$ /index.html [QSA]

    RewriteRule ^([^.]+)$ $1.html [QSA]

    RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f

    RewriteRule ^/(.*)$ balancer://mongrel_cluster%{REQUEST_URI} [P,QSA,L]

    ErrorLog /var/log/apache2/error.log

    # Possible values include: debug, info, notice, warn, error, crit,
    # alert, emerg.
    LogLevel warn

    CustomLog /var/log/apache2/access.log combined
    ServerSignature Off

    </VirtualHost>
  26. Dann musst du in /etc/apache2/mods-enabled folgende Symlinks anlegen:

    ln -s ../mods-available/proxy_balancer.load
    ln -s ../mods-available/proxy.conf
    ln -s ../mods-available/proxy_http.load
    ln -s ../mods-available/proxy.load
    ln -s ../mods-available/rewrite.load

    Der Inhalt der proxy.conf muss so aussehen:

    <IfModule mod_proxy.c>
    #turning ProxyRequests on and allowing proxying from all may allow
    #spammers to use your proxy to send email.

    ProxyRequests Off

    <Proxy *>
    AddDefaultCharset off
    Order allow,deny
    Allow from all
    </Proxy>

    # Enable/disable the handling of HTTP/1.1 "Via:" headers.
    # ("Full" adds the server version; "Block" removes all outgoing Via: headers)
    # Set to one of: Off | On | Full | Block

    ProxyVia On
    </IfModule>

  27. Dann nur noch Apache neu starten:

    /etc/init.d/apache2 restart

  28. Feierabend. Das wars.


Wenn du jetzt eine neue Version deiner Anwendung live stellen willst, musst du nur in deinem Rails Projektverzeichnis

cap deploy

bzw

cap deploy:migrations

ausfuehren wenn es neue Datenbankmigrationen gibt. Capistrano macht dann den Rest!

Bitte benutze die Kommentarfunktion wenn du beim Folgen dieser Schritte ein paar Tipps oder Probleme gefunden hast.
Grosser Dank gilt noch dem grossartigen Tutorial von Coda. Da gibt es noch sehr viel Hintergrundinfos. Ich wollte das hier nicht alles wiederholen, sondern es eher kurz und knapp halten. Ich hoffe, dass es ganz hilfreich ist.

Wenn das der Fall ist würde ich mich sehr über eine Empfehlung freuen:
Recommend Me
Danke!

Friday, April 11, 2008

My Experience as a Rails Coach

It's Thursday night and I'm typing this at the Munich airport waiting for my flight to Hamburg. I've spent the last 3 days in Bavaria helping two talented PHP developers getting started with Ruby on Rails. It was fun.
On the first day I gave a brief introduction to OOP and TDD along with a quick Rails overview. Then we started coding. We set up Subversion, and coded two demo projects by noon, touching on RESTful design and scaffolding, migrations, MVC, tests, and the joy of having ActiveRecord do all the dirty CRUD work. One of the developers then told me that they were very sceptic at first as to why Rails would improve or speed up their development in comparison to PHP. But those few hours already had convinced him why. That was a very satisfying experience.
On the second day the same developer had the idea of following through the Depot application demo from the AWDWR book and recording what I do as a screencast. That was a great idea. So we started with the Depot application from scratch, using the new Rails 2.0 way of doing things where necessary or where it made sense. We got to the end of Task C on page 109 on the first day and finished the complete Depot application today with testing and all.
So in 3 days we covered A LOT of ground and I have screencasts of developing the whole Depot application with Rails 2. They are pretty raw and they are in German, but they might be helpful to some (if you don't mind my stinking slow iBook and my lame jokes along the way). I'm thinking about making them available on my blog soon.
Well, the bottom line is Rails is great and in 3 days you can give a great introduction to this framework with quite a bit of in-depth information.

Tuesday, March 4, 2008

Developing Ruby on Rails on Mac OS X Leopard, or DRoRoMOSXL

I just received the new ADC newsletter and it had a link to a very nice tutorial for developing Ruby on Railsleopard applications on Leopard. There are heaps of RoR tutorials out there, but in my experience tutorials written by the Apple folks are of an above average quality.
Another interesting thing about this tutorial is that it uses XCode 3.0 instead of my (and I guess most people's) Mac text editor of choice, TextMate. It's the first of three parts. So to whom it may concern, it might be an interesting read.

Friday, November 2, 2007

Rails, Capistrano and svn+ssh agent forwarding

I was working on deploying a Rails application using Capistrano today. I ran into a few problems because my SVN server uses svn+ssh authentication. I will not go into all the details of using Mongrel and Capistrano, I'll just touch on the points that are important for using it with svn+ssh.
The problem is this: Capistrano logs in to your deployment server and wants to check out your Rails project from your SVN server. If that SVN server uses svn+ssh authentication, you need to enter a password, but since Capistrano is issuing the command, you can't enter that password and everything fails. You'll see something like this:

** [out :: 192.168.0.200] subversion is asking for a password

The solution I used was to use SSH public key authentication instead. Here's a great tutorial.
Once that's done, you only need your private key on your client and the public key on your SVN server.
Now you either keep following the tutorial to set up ssh agent forwarding or you take the easy way and download SSHKeychain for your Mac.
Install it using these instructions (don't forget to enable "Manage global environment variables" in SSHKeychain's Preferences), add it to your Mac's Login Items, log out of your Mac session, and log in again.

If everything with the keys is set up correctly, you should be able to log in to your SVN server through Terminal.app without being asked for a password.

Ok, now you have to tell Capistrano that it should use ssh agent forwarding. That is required for Capistrano to be able to log in to your SVN server using your key and not requiring a password.

So open up deploy.rb and add this line to the SSH OPTIONS section:

ssh_options[:forward_agent] = true


If cap cold_deploy works now: great. In my case, it threw a strange exception like this one:

Net::SSH::Transport::Session: [:forward_agent] (ArgumentError)

That means your net-ssh ruby gem is too old. I think it has to be at least version 1.1.1. So after running

gem update net-ssh


cap cold_deploy worked like a charm!

This great tutorial also helped me a lot.