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

Thursday, May 22, 2008

Today I bought an enterprise license of mod_rails (Phusion Passenger)

I think it's the coolest piece of server software, right after apache and rails!

mod_rails

C'mon support those guys - they just made our lives (deployment-wise) much easier.

Getting Javascript and CSS files working with passenger (locally)

After looking around why my .js or .css files won't load, I found that my Apache's error_log had a lot of these lines:

[Thu May 22 01:27:26 2008] [error] [client 127.0.0.1] client denied by server configuration: /Users/art/development/projects/rails/rchat/public/javascripts/application.js, referer: http://rchat_prod.local/

Adding AllowOverride and the Order directives, fixed it:

<VirtualHost *>
ServerName rchat_prod.local
DocumentRoot /Users/art/development/projects/rails/rchat/public
<Directory "/Users/art/development/projects/rails/rchat/public"%gt;
Options FollowSymLinks
AllowOverride None
Order allow,deny
Allow from all
</Directory>
</VirtualHost>

Saturday, October 13, 2007

How to get a working Rails 1.2.5

After today's

gem update


I repeatedly got the same annoying error message again and again:

Install required dependency activesupport? [Yn] Y
ERROR: While executing gem ... (Gem::GemNotFoundException)
Could not find activesupport (= 1.4.3.7843) in any repository


The fix is however simply - just specifiy a source server for the packages (where Rails 1.2.5 can already be found):

gem install rails --version '= 1.2.5' --source http://gems.rubyonrails.org/ -y


Problem sovled - let's get back preparing Rails 1.2.x application for the migration to Rails 2.0

Update 1 - There are again failing updates!
To resolve this fully, just get rid of everything old and reinstall:

gem uninstall rails (select "all")
gem install rails -y --source http://gems.rubyonrails.org/

Thursday, August 23, 2007

Classloader issues in rails

Once upon a time, everybody gets hit by a train!
The classloader train on rails!

That's when everything works on your development workstation, in development and production mode, but it won't work on your production system.
That's when you check every line of your controllers code, every line of your models code.

But don't fear, there is an easy way to debug this and an easy way to prevent this in the future!

How to debug this:
Since ruby is a really really code language, try this:
Put a puts statement before and after your class!

puts 'start loading account_class'
class Account < ActiveRecord::Base
# your code here
end


Once you're finished, just try this:

script/console


You will see something like this:

devws:/development/projects/demo art$ script/consoleLoading development environment.
start loading account
end loading account
start loading xxx
end loading xxx


Now login to your production, errr, integration system, and try this again.
One thing that really shocked me, was:
On Mac OSX (my workstation) every model was loaded.
On Linux (my production system) one model was missing!

Okay, I just had 19 models, so it was easy to track down the missing class :)

But, you can go even further - put a puts statement before and after your methods:

puts 'start loading account_class'
class Account < ActiveRecord::Base
puts 'before doSomethingWithADifferentClass'
def doSomethingWithADifferentClass
end
puts 'after doSomethingWithADifferentClass'
end


That's how you can track down, if your methods get fully loaded.


How to prevent this in the future:
1) Put your requires where the belong (environments.rb could be loaded after your model class)
2) Put your require statements in the classes that need them
3) Be careful when you use memcached -> when you unmarshal an object (get it out of memcached) the class needs to be loaded first!

One additional info:
In development mode, all classes are reloaded everytime. In production mode classes are only loaded once :)


My models and even my controllers have now their require statements - I hope this help a bit!


As usual, once you know what hits you, you know how to search for more information and find these resources:
http://duncandavidson.com/archives/285
http://mojodna.net/2007/02/12/classloading-in-rails/