Saturday, July 5, 2008

sqlite3 won't load on Ruby Enterprise Edition - but there's a solution

After several days runing mod_rails successfully on my server, I decided it was time to switch to Ruby Enterprise Edition from Phusion.
* It would provide the long outstanding correct bugfix for several security flaws in ruby (without breaking rails support [1,2,3]).
* It would also decrease the memory requirements on the server itself.

Here is my (old) configuration of mod_rails with standard ruby:

LoadModule passenger_module /usr/lib/ruby/gems/1.8/gems/passenger-2.0.1/ext/apache2/mod_passenger.so
PassengerRoot /usr/lib/ruby/gems/1.8/gems/passenger-2.0.1
PassengerRuby /usr/bin/ruby1.8
RailsEnv production
RailsMaxPoolSize 10
RailsPoolIdleTime 120

So after installing Ruby Enterprise Edition for Ubuntu, I only had to change one line:

#PassengerRuby /usr/bin/ruby1.8
PassengerRuby /opt/ruby-enterprise-1.8.6-20080624/bin/ruby

I restarted apache (just to be sure).

The result was not what I actually expected:
sqlite3 won't load on REE

A quick check on the FAQ's on Pushion#s homepage revealed some hints - but I had already done that.

The actual problem
The problem wasn't the ruby enterprise edition (although only err shown the different behaviour), the source of the problem is the sqlite3-ruby gem itself. It doesn't contain read-rights on some files (oh dear maintainer!).

root@server:/opt/ruby-enterprise-1.8.6-20080624/lib/ruby/gems/1.8/gems# cd sqlite3-ruby-1.2.2/
root@server:/opt/ruby-enterprise-1.8.6-20080624/lib/ruby/gems/1.8/gems/sqlite3-ruby-1.2.2# find . -perm 0662 -exec ls -l {} \;

-rw-rw--w- 1 root root 3738 Jul 1 00:54 ./lib/sqlite3/translator.rb
-rw-rw--w- 1 root root 24774 Jul 1 00:54 ./lib/sqlite3/database.rb
-rw-rw--w- 1 root root 3174 Jul 1 00:54 ./doc/faq/faq.rb
-rw-rw--w- 1 root root 10744 Jul 1 00:54 ./ext/sqlite3_api/sqlite3_api.i
-rw-rw--w- 1 root root 457 Jul 1 00:54 ./ext/sqlite3_api/extconf.rb
-rw-rw--w- 1 root root 33308 Jul 1 00:54 ./test/tc_integration.rb
-rw-rw--w- 1 root root 541 Jul 1 00:54 ./test/tc_errors.rb

The fix
Just add read-permissions to the files:

root@server:/opt/ruby-enterprise-1.8.6-20080624/lib/ruby/gems/1.8/gems/sqlite3-ruby-1.2.2# find . -perm 0662 -exec chmod 664 {} \;


Everything is now up-and-running smoothly for 4 days now - thanks to mod_rails and Ruby Enterprise Edition from Phusion.

Productivity boost for Rails developers - or - How I work

Here is the shell script I use to start my Rails development environment (requires iTerm and TextMate).
Just replace FULL_PATH_TO_PROJECT_ON_DISK with the path to your project and give it a name: PROJECT_NAME.

It will open iTerm with 4 shell, and it will run:
* Textmate in the root of the project, so that all project files are listed in textmate
* the rails server will be started
* the console will be launched
* the database console will be launched


#!/bin/sh
PROJECT_DIR=FULL_PATH_TO_PROJECT_ON_DISK
PROJECT_NAME=PROJECT_NAME

osascript <<-eof
tell application "iTerm"
make new terminal
tell the last terminal
activate current session

launch session "Default Session"
tell the last session
set name to "$PROJECT_NAME-project-root"
write text "cd \"$PROJECT_DIR\""
write text "mate ."
write text "clear; ls -lah"
end tell

launch session "Default Session"
tell the last session
set name to "$PROJECT_NAME-server"
write text "cd \"$PROJECT_DIR\""
write text "clear"
write text "./script/server"
end tell

launch session "Default Session"
tell the last session
set name to "$PROJECT_NAME-console"
write text "cd \"$PROJECT_DIR\""
write text "clear"
write text "./script/console"
end tell

launch session "Default Session"
tell the last session
set name to "$PROJECT_NAME-database"
write text "cd \"$PROJECT_DIR\""
write text "clear"
write text "./script/dbconsole"
end tell

end tell
end tell

tell application "TextMate"
activate
end tell
eof

Friday, July 4, 2008

MySQL ENCRYPT function in Ruby (for Rails)

Zhe backend system required that the password column used the MySQL ENCRYPT function. Since I didn't wanted to hack rails to much, I just aded the required code into the rails model directly - 5 minutes work, voila.

When the password get's assigned, it is automatically "MySQL encrypted". Here's ther code for reference:

def password=(pw)
self[:password] = mysql_encrypt(pw)
end

private
def mysql_encrypt(pw)
salt = [Array.new(6){rand(256).chr}.join].pack("m").chomp
return pw.crypt(salt)
end