Installing and configuring Ruby on Rails

Ruby on Rails requires:

  • Ruby (the programming language)
  • RubyGems (This the standard Ruby package manager. It's similar to apt-get, emerge, and other OS package managers.)

I have closely followed the instructions of the book “Agile Web Development With Rails” to get Ruby on Rails installed.

Compiling Ruby

Of course, Ruby on Rails needs Ruby.

[root@1038 src]# wget http://rubyforge.org/frs/download.php/7858/ruby-1.8.4.tar.gz

From here one, just do the usual open-source build:

[root@1038 src]# cd ruby-1.8.4
[root@1038 ruby-1.8.4]# ./configure
[root@1038 ruby-1.8.4]# make
[root@1038 ruby-1.8.4]# make test
[root@1038 ruby-1.8.4]# make install

Wrapping Up: RubyGems and Using Webrick

The book tells you exactly how to install Rails. Here's an example:

[root@1038 woordenweb]# gem install rails
Attempting local installation of 'rails'
Local gem file not found: rails*.gem
Attempting remote installation of 'rails'
Updating Gem source index for: http://gems.rubyforge.org
Install required dependency activerecord? [Yn]  Y
Install required dependency actionpack? [Yn]  Y
Install required dependency actionmailer? [Yn]  Y
Install required dependency actionwebservice? [Yn]  Y
Successfully installed rails-1.1.5
Successfully installed activerecord-1.14.4
Successfully installed actionpack-1.12.4
Successfully installed actionmailer-1.2.4
Successfully installed actionwebservice-1.1.5
Installing RDoc documentation for activerecord-1.14.4...
Installing RDoc documentation for actionpack-1.12.4...
Installing RDoc documentation for actionmailer-1.2.4...
Installing RDoc documentation for actionwebservice-1.1.5...

I have installed RubyGems as per the book. After that, I tested the Ruby on Rails installation by using the Ruby based webrick server:

[root@1038 demo]# ruby script/server
=> Booting WEBrick...
=> Rails application started on http://0.0.0.0:3000
=> Ctrl-C to shutdown server; call with --help for options
[2006-05-02 09:50:28] INFO  WEBrick 1.3.1
[2006-05-02 09:50:28] INFO  ruby 1.8.4 (2005-12-24) [i686-linux]
[2006-05-02 09:50:28] INFO  WEBrick::HTTPServer#start: pid=14537 port=3000

Installing the MySQL Gem

Apparently, Ruby on Rails also needs the “MySQL Gem”.

[root@1038 depot]# gem install mysql
Attempting local installation of 'mysql'
Local gem file not found: mysql*.gem
Attempting remote installation of 'mysql'
Updating Gem source index for: http://gems.rubyforge.org
Select which gem to install for your platform (i686-linux)
 1. mysql 2.7.2006.04.21 (mswin32)
 2. mysql 2.7 (ruby)
 3. mysql 2.6 (ruby)
 4. mysql 2.5.1 (ruby)
 5. Cancel installation
> 2
Building native extensions.  This could take a while...
ruby extconf.rb install mysql
checking for mysql_query() in -lmysqlclient... yes
checking for mysql_ssl_set()... yes
checking for mysql.h... no
checking for mysql/mysql.h... yes
creating Makefile
 
make
gcc -fPIC -g -O2  -I. -I/usr/local/lib/ruby/1.8/i686-linux -I/usr/local/lib/ruby/1.8/i686-linux -I. -DHAVE_MYSQL_SSL_SET -DHAVE_MYSQL_MYSQL_H -I/usr/local/include  -c mysql.c
gcc -shared  -L'/usr/local/lib' -Wl,-R'/usr/local/lib' -L'/usr/local/lib' -Wl,-R'/usr/local/lib' -o mysql.so mysql.o  -lmysqlclient  -ldl -lcrypt -lm   -lc
 
make install
mkdir -p /usr/local/lib/ruby/gems/1.8/gems/mysql-2.7/lib
/usr/bin/install -c -m 0755 mysql.so /usr/local/lib/ruby/gems/1.8/gems/mysql-2.7/lib
Successfully installed mysql-2.7

Problems with Installing the MySQL Gem

On another system, I had troubles getting the mysql gem installed.

A posting on weblog.rubyonrails.com, weblog.rubyonrails.com, suggested this: ruby extconf.rb –with-mysql-dir=/opt/lampp/bin, but that lead to this output:

daforeignmachine:/opt/lampp/lib/ruby/gems/1.8/gems/mysql-2.7 # ruby extconf.rb --with-mysql-dir=/opt/lampp                                      /bin
checking for mysql_query() in -lmysqlclient... no
checking for main() in -lm... yes
checking for mysql_query() in -lmysqlclient... no
checking for main() in -lz... yes
checking for mysql_query() in -lmysqlclient... no
checking for main() in -lsocket... no
checking for mysql_query() in -lmysqlclient... no
checking for main() in -lnsl... yes
checking for mysql_query() in -lmysqlclient... no
*** extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of
necessary libraries and/or headers.  Check the mkmf.log file for more
details.  You may need configuration options.

Provided configuration options:
        --with-opt-dir
        --without-opt-dir
        --with-opt-include
        --without-opt-include=${opt-dir}/include
        --with-opt-lib
        --without-opt-lib=${opt-dir}/lib
        --with-make-prog
        --without-make-prog
        --srcdir=.
        --curdir
        --ruby=/opt/lampp/bin/ruby
        --with-mysql-config
        --without-mysql-config
        --with-mysql-dir
        --with-mysql-include
        --without-mysql-include=${mysql-dir}/include
        --with-mysql-lib
        --without-mysql-lib=${mysql-dir}/lib
        --with-mysqlclientlib
        --without-mysqlclientlib
        --with-mlib
        --without-mlib
        --with-mysqlclientlib
        --without-mysqlclientlib
        --with-zlib
        --without-zlib
        --with-mysqlclientlib
        --without-mysqlclientlib
        --with-socketlib
        --without-socketlib
        --with-mysqlclientlib
        --without-mysqlclientlib
        --with-nsllib
        --without-nsllib
        --with-mysqlclientlib
        --without-mysqlclientlib

My hypothesis is: the mysql client developer's libraries are not installed. A little web searching yields this result:

“Those errors are usually caused by one of those two things: gcc is not installed or libmysqlclient14-dev (mysql client developer’s libraries) are not installed.”

Lazycoder blog: Ruby on rails error

In my case, I had to install the mysql client developer’s libraries.

More Trouble With MySQL

Turns out that Rails wants the mysql.sock file in a specific place, namely /tmp/mysql.sock. If your mysql.sock file is located elsewhere, simply make a symbolic link to the actual location. E.g.:

myhost:/tmp# ln -s /var/run/mysqld/mysqld.sock mysql.sock
myhost:/tmp# ls -lah
total 816K
drwxrwxrwt   5 root     root     1.0K Jul 18 19:10 .
drwxr-xr-x  20 root     root     1.0K May 10 01:10 ..
lrwxrwxrwx   1 root     root       27 Jul 18 16:08 mysql.sock -> /var/run/mysqld/mysqld.sock

However, /tmp/ being what it is (a temporary directory), its content tends to get deleted every once in a while. So a much better solution is the following:

SOLVED: More Trouble With MySQL

Just specify the correct path to the socket in config/database.yml!

Example:

production:
  adapter: mysql
  database: myproject_production
  encoding: utf8
  username: myproject_user
  password: 
  host: localhost
  socket: /var/run/mysqld/mysqld.sock

Faster Ruby on Rails: FastCGI

For real life production servers, it is recommended to use FastCGI. Because I had Apache already running, I decided to install FastCGI as an Apache module.

This website deals (not exclusively) with installing FastCGI for Ruby on Rails:

http://www.easy-designs.net/articles/WesthostOnRails/

It is almost entirely correct, except for the changes which the author recommends for the file dispatch.fcgi.

Installing FastCGI was not exactly easy and because I am afraid the afore mentioned website may one day disappear, I have copied some instructions verbatimly.

Installing FastCGI

We need to install the FastCGI Dev Kit. To do that, enter its directory, configure and install it similarly to how we did Ruby:

[~]$ cd fcgi-2.4.0
[fcgi-2.4.0]$ ./configure --prefix=/usr/local/fcgi
[fcgi-2.4.0]$ make && make install

Next on the agenda is getting Apache to understand FastCGI. To do this, we need to compile and install the DSO for Apache, which uses a slightly different process:

[root@1038 mod_fastcgi-2.4.2]# /www/bin/apxs -i -a -n fastcgi mod_fastcgi.so
[activating module `fastcgi' in /www/conf/httpd.conf]
cp mod_fastcgi.so /www/libexec/mod_fastcgi.so
chmod 755 /www/libexec/mod_fastcgi.so
cp /www/conf/httpd.conf /www/conf/httpd.conf.bak
cp /www/conf/httpd.conf.new /www/conf/httpd.conf
rm /www/conf/httpd.conf.new
[root@1038 mod_fastcgi-2.4.2]#

Then install the Ruby-FastCGI Gem:

[root@1038 bin]# gem install fcgi
Attempting local installation of 'fcgi'
Local gem file not found: fcgi*.gem
Attempting remote installation of 'fcgi'
Building native extensions.  This could take a while...
ruby extconf.rb install fcgi
checking for fcgiapp.h... yes
checking for FCGX_Accept() in -lfcgi... yes
creating Makefile
 
make
gcc -fPIC -g -O2  -I. -I/usr/local/lib/ruby/1.8/i686-linux -I/usr/local/lib/ruby/1.8/i686-linux -I. -DHAVE_FCGIAPP_H  -c fcgi.c
gcc -shared  -L'/usr/local/lib' -Wl,-R'/usr/local/lib' -o fcgi.so fcgi.o  -lfcgi  -ldl -lcrypt -lm   -lc
 
make install
/usr/bin/install -c -m 0755 fcgi.so /usr/local/lib/ruby/gems/1.8/gems/fcgi-0.8.6.1/.
Successfully installed fcgi-0.8.6.1
Installing RDoc documentation for fcgi-0.8.6.1...
 
No definition for fcgi_s_accept
 
(... same kind of messages ...)
 
No definition for fcgi_stream_setsync

Configuring Apache

We need to add the handler for FastCGI to httpd.conf, so scroll down in this file until you see some other AddHandler statements (or run a search) and insert the following:

AddHandler fastcgi-script fcg fcgi fpl

Then, create an instance of our demo app near the bottom of the httpd.conf file:

# FastCGI
<IfModule mod_fastcgi.c>
  FastCgiIpcDir /tmp/fcgi_ipc
  FastCgiServer /home/solin/domains/rails.solin.nl/demo/public/dispatch.fcgi -initial-env RAILS_ENV=development -processes 1 -idle-timeout 60
  #FastCgiServer /home/solin/domains/rails.solin.nl/demo/public/dispatch.fcgi -initial-env RAILS_ENV=production -processes 1 -idle-timeout 60
</IfModule>

I have experimented with the above settings. They refer directly to specific virtual hosts, which is very inconvenient. You can leave them out. You probably only need the line FastCgiIpcDir /tmp/fcgi_ipc.

A further addition is the entry for our demo website:

<VirtualHost 213.193.214.124:80>
  ServerName rails.solin.nl
  ServerAlias www.rails.solin.nl
  DocumentRoot /home/solin/domains/rails.solin.nl/demo/public
  ErrorLog /home/solin/domains/rails.solin.nl/logs/error_log
  CustomLog /home/solin/domains/rails.solin.nl/logs/access_log combined  
  <Directory /home/solin/domains/rails.solin.nl/demo/public>
      Options ExecCGI FollowSymLinks
      AllowOverride all
      Allow from all
      Order allow,deny
  </Directory>
</VirtualHost>

The section within ”<Directory>” is very important: Ruby on Rails depends on .htaccess files for rewriting url. In other words: ”AllowOverride all” is crucial.

Now, to set up Rails to use FastCGI, we need to edit the .htaccess file in the public folder. In that file, change:

RewriteRule ^(.*)$ dispatch.cgi [QSA,L]

to:

RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]

That's it. Do not make the changes in the file dispatch.fcgi as the author of the website recommends.

Test the configuration:

[root@1038 bin]# /www/bin/apachectl configtest
[Mon May  1 20:38:18 2006] [warn] module mod_fastcgi.c is already added, skipping
[Mon May  1 20:38:18 2006] [warn] NameVirtualHost 213.193.214.125:80 has no VirtualHosts
Syntax OK

And restart Apache:

[root@1038 bin]# /www/bin/apachectl restart
/www/bin/apachectl restart: httpd restarted

SCGI for faster Rails

An alternative method for improving Rails' speed is scgi.

Start scgi processes through:

host:/rails_apps/my_app/ # scgi_ctrl start

Please remember that your Rails application also contains a config/scgi.yaml file. Do not forget to back up this file if you ever reinstall your Rails app.

Mongrel for faster Rails (and Pen for better load balancing under Apache 2.0)

Nowadays, people don't use FastCGI anymore apparently. Mongrel provides far better performance it is rumored (okay, people have run tests to figure this out – see Google). A popular way of installing and configuring Rails is:

  • Mongrel webserver
  • Apache webserver
  • A load balancing mechanism, e.g. as provided by Apache 2.2

I have Apache 2.0.x on my Debian Stable (Sarge) host, so I can't use Apache's load balancing facilities. Instead, I use Pen. To get my Rails applications to run fast on Debian Sarge, I followed the instructions on this website:

Mongrel, Apache and Rails on Debian Sarge

I had relatively little trouble getting it all installed. There's one minor annoyance though: Mongrel is really interwoven with your Rails app, just like your local Webrick webserver. If your Rails app is not properly installed, the Mongrel “instance” for your application will not run.

To follow the instructions on the website mentioned above, I had to install the mod_enabled Apache module. I used the a2enmod command to do this.

root@lappy:~# a2enmod enabled
Module enabled installed; run /etc/init.d/apache2 force-reload to enable.

It's also nice to see a complete working example of an Apache virtual host section so here goes:

<VirtualHost *:80>
ServerName smallcount.myhost.com
ServerAlias www.smallcount.myhost.com
DocumentRoot /home/myhost/domains/smallcount.myhost.com/smallcount/public

## Fix for Apache bug 39499
#SetEnv force-proxy-request-1.0 1
#SetEnv proxy-nokeepalive 1

## mod_proxy config
ProxyRequests Off
<Proxy *>
  Order deny,allow
  Allow from all
</Proxy>

## send all requests to URIs not corresponding to real files to the load balancer:
RewriteEngine On
RewriteRule ^/$ /index.html [QSA]
RewriteRule ^([^.]+)$ $1.html [QSA]
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME}   !-f
## 8001 is the proxy_port from mongrel configuration of your app
RewriteRule .* http://localhost:8001%{REQUEST_URI} [P,QSA]
</VirtualHost>

(Please remember to restart your Apache webserver after changing the configuration files).

Testing and Troubleshooting Mongrel

First you have to know how to start mongrel. Mongrel lives in /etc/mongrel. The websites powered by mongrel are defined in /etc/mongrel/sites-enabled. Start mongrel like this:

/etc/mongrel/sites-enabled# /etc/init.d/mongrel restart YOUR_SITE_CONFIG_FILE.cfg

If anything goes wrong, try to start your website manually so you'll see mongrel's output. Example:

/etc/mongrel/sites-enabled# /usr/bin/ruby1.8 /usr/bin/mongrel_rails start -e production -a 127.0.0.1 -c /home/myhost/domains/mysite.myhost.com/mysite
** Starting Mongrel listening at 127.0.0.1:3000
** Starting Rails with production environment...
/usr/lib/ruby/1.8/yaml.rb:133:in `load': syntax error on line 16, col 11: `  encoding: utf8' (ArgumentError)

Running Two (or more) Rails Applications with Mongrel

The short version: simply increase all port numbers in all configurations files. As an example, here's the smallcount.conf mongrel configuration file for the example app mentioned above:

# RAILS_ROOT of your application
dir=/myhome/myhost/domains/smallcount.myhost.com/smallcount/public
# port the first mongrel instance should listen to, additional instances will use ports above this
port=8100
# number of mongrel instances
servers=3
# port pen will listen on
proxy_port=8001

Remember the proxy port, because that's the one we're gonna reference in the Apache virtual host configuration file:

ServerName smallcount.myhost.com
ServerAlias www.smallcount.myhost.com
DocumentRoot /myhome/myhost/domains/smallcount.myhost.com/smallcount/public

## Fix for Apache bug 39499
#SetEnv force-proxy-request-1.0 1
#SetEnv proxy-nokeepalive 1

## mod_proxy config
ProxyRequests Off
<Proxy *>
  Order deny,allow
  Allow from all
</Proxy>

## send all requests to URIs not corresponding to real files to the load balancer:
RewriteEngine On
RewriteRule ^/$ /index.html [QSA]
RewriteRule ^([^.]+)$ $1.html [QSA]
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME}   !-f
## 8001 is the proxy_port from mongrel configuration of your app
RewriteRule .* http://localhost:8001%{REQUEST_URI} [P,QSA]

Now if you add a second rails application, just increase all the port numbers by one:

# RAILS_ROOT of your application
dir=/myhome/myhost/domains/woordenweb.myhost.com/woordenweb/public
# port the first mongrel instance should listen to, additional instances will use ports above this
port=8200
# number of mongrel instances
servers=3
# port pen will listen on
proxy_port=8002

And in your Apache configuration file too:

ServerName woordenweb.myhost.com
ServerAlias www.woordenweb.myhost.com
DocumentRoot /myhome/myhost/domains/woordenweb.myhost.com/woordenweb/public

## Fix for Apache bug 39499
#SetEnv force-proxy-request-1.0 1
#SetEnv proxy-nokeepalive 1

## mod_proxy config
ProxyRequests Off
<Proxy *>
  Order deny,allow
  Allow from all
</Proxy>

## send all requests to URIs not corresponding to real files to the load balancer:
RewriteEngine On
RewriteRule ^/$ /index.html [QSA]
RewriteRule ^([^.]+)$ $1.html [QSA]
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME}   !-f
## 8002 is the proxy_port from mongrel configuration of your app
RewriteRule .* http://localhost:8002%{REQUEST_URI} [P,QSA]

Simple Configuration for Running Two or More Applications with Mongrel under Apache 2.2

Here's how to run two (or more) rails applications with Mongrel.

  1. Start a Mongrel instance ('process') for each application
  2. Configure your Apache httpd-vhosts.conf file and restart Apache

1. Install Mongrel:

sudo gem install mongrel

Then move to the directory where your rails app is in (the directory just above app). Now, issue this command:

  mongrel_rails start -d -p 8000 -e production

The -d options means 'daemonize' (or detach). If you don't use this option, the mongrel instance will shut down once you exit your terminal. Repeat for each app, but increase the port number by 1 each time, and remember the port numbers for each app.

If you're ready, issue this command: ps -ef |grep mongrel. You should see all your mongrel instances now:

  > ps -ef |grep mongrel
  root     20733     1  0 21:00 ?        00:00:04 /opt/lampp/bin/ruby /opt/lampp/bin/mongrel_rails start -e development -d -p 8002
  root     20862     1  0 21:59 ?        00:00:02 /opt/lampp/bin/ruby /opt/lampp/bin/mongrel_rails start -d -p 8003 -e production

N.B.: try to avoid running the mongrels as root.

2. Your applications are going to served up by Apache first. Apache should handle all the static content (images, stylesheets, javascripts, flash files, etc.), and pass on all dynamic requests to mongrel. So, you're going to need mod_proxy. Here's an example of a virtual host entry in httpd-vhosts.conf file:

  <VirtualHost *:80>
    
    ServerName suppappa.com
    ServerAlias www.suppappa.com
    DocumentRoot /path/to/rails_app/suppappa/public
    
    
    ProxyPass / http://suppappa.com:8002/
    ProxyPassReverse / http://suppappa.com:8002
    ProxyPreserveHost on    

    ProxyPass /images ! 
    ProxyPass /stylesheets !
    ProxyPass /javascripts !
    ProxyPass /flash !
    #continue with other static files that should be served by apache

    Alias /images /path/to/rails_app/suppappa/public/images
    Alias /stylesheets /path/to/rails_app/suppappa/public/stylesheets
    Alias /javascripts /path/to/rails_app/suppappa/public/javascripts
    Alias /flash /path/to/rails_app/suppappa/public/flash
    #continue with aliases for static content
	     
  </VirtualHost>

Now all you have to do is restart Apache (e.g. apachectl restart).

Debian / Ubuntu users attention! Make sure that proxy.conf is configured to allow reverse proxying! See the Apache 2.2 documentation for mod_proxy.

<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 *>
          Order deny,allow
          #Deny from all
          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>

The default for Debian / Ubuntu is Deny from all, but that should be changed to Allow from all.

N.B.: if you need to restart mongrel, just run mongrel_rails stop and mongrel_rails start -e development -d -p 8002 (or whatever mode and port number you're using).

Which Version?

If you want to know which version you just installed, do rails -v on the command line. If you want to know, 100% sure, which version of Rails your application is actually using, add this in one of your views:

 Rails version: <%= RAILS_GEM_VERSION.to_s %>

Installing Other Rails Versions Using Gem

To install a specific Rails version (instead of just the latest stable version), use the -v parameter:

gem install rails -v 1.1.6

In the same way, you can also uninstall specific rails versions:

gem uninstall rails -v 1.2.0

To list all versions currently installed, do gem list rails:

 gem list rails

*** LOCAL GEMS ***

rails (1.2.2, 1.1.6)
    Web-application framework with template engine, control-flow layer,
    and ORM.

Rails on Ubuntu Linux

This is pretty straightforward. Just install the RoR package through the Synaptic Package Manager, as well as RubyGems (manual installation only, download here).

Finally, you must also install libmysql-ruby using the Synaptic Package Manager. That's it.

Phusion Passenger Under Ubuntu Linux

Follow the instructions from the guys from Phusion: www.modrails.com. There are several pitfalls:

  • PassengerDefaultUser: if you experience starting problems, set PassengerDefaultUser (inside a <VirtualHost>) to your Apache user (e.g. www-data)
  • Delete old /tmp/ruby_sess.* files
  • Delete the .htaccess file from your Rails public directory (or the assets, such as images, will not show up)
  • Apparently, Phusion Passenger is not compatible with mod_rewrite / mod_alias. See: modrails.com
  • By default, mod_rails runs in production mode. Use RailsEnv development (inside a <VirtualHost>) to set it to development mode.

That's it.

Ruby Enterprise

Install Ruby Enterprise to complement modrails. From the nice guys of Phusion!

Only possible issue: Ruby Enterprise is installed completely separately from your existing Ruby stuff. So, all your currently installed gems are not used by Ruby Enterprise. According to this site, you can do:

/opt/ruby-enterprise-1.8.6-20080810/bin/gem install mislav-will_paginate

Or you can symlink to the correct version:

ln -fs /opt/ruby-enterprise-1.8.6-20080810 /opt/ruby-enterprise
ln -fs /opt/ruby-enterprise/bin/gem /usr/bin/gem
ln -fs /opt/ruby-enterprise/bin/irb /usr/bin/irb
ln -fs /opt/ruby-enterprise/bin/rake /usr/bin/rake
ln -fs /opt/ruby-enterprise/bin/rails /usr/bin/rails
ln -fs /opt/ruby-enterprise/bin/ruby /usr/bin/ruby

Personal Tools