Deploying Rails to Tomcat as a WAR with JRuby

Assumptions

  • You are experienced with Java and have at least dabbled around with Ruby on Rails.
  • These steps worked for me on a Mac OS X 1.0.4.9 system
  • I’ve walked through the steps 3 times from scratch, but your mileage may still vary.

Install and Configure JRuby

First step download install JRuby. You can get it at:

  • http://dist.codehaus.org/jruby/

After pulling down the tarball,

1
jruby-bin-1.0.0RC2.tar.gz

, I unpacked it and installed at:

  • 1
    /Applications/jruby1.0.2RC

Next, add the environment variable

1
JRUBY_HOME

to point to

1
/Applications/jruby1.0.2RC

. I added it to my

1
.bash_profile

since I’m running the bash shell by default on Mac OS X:

1
2
# JRuby<br />
export JRUBY_HOME=/Applications/jruby1.0.0RC2

Since I don’t want to take out my normal Ruby C install I just export it in front of the path just for this terminal session:

1
export PATH=$JRUBY_HOME/bin:$PATH

Double check that JRuby is setup:

1
jruby --version

This should return something like:

1
ruby 1.8.5 (2007-05-16 rev 3672) [i386-jruby1.0.0RC2]

Test With A Simple JRuby App

Go ahead and setup a directory for your JRuby apps:

1
2
3
4
cd ~<br />
mkdir jruby_stuff<br />
cd jruby_stuff<br />
mate test_java.rb

The last step assumes your using textmate. You can replace it with any

1
vi

or any other editor you want.

Write a small JRuby app and save it:

[ruby]
require ‘java’
include_class ‘java.util.ArrayList’
list = ArrayList.new
list.add “Ruby”
list.add “+”
list.add “Java”
list.add “=”
list.add “JRuby”
list.each do |word|
puts “#{word}”
end
[/ruby]

Go ahead and run the simple ruby script and test the java integration of JRuby:

1
jruby test_java.rb

Should see:

1
2
3
4
5
Ruby<br />
+<br />
Java<br />
=<br />
JRuby<br />

Rails Setup

Run:

1
gem install rails -y --no-ri --no-rdoc

This should take about a minute. There are lots of notes on how ri and Rdoc take a long time to run right now, but it wasn’t too bad, about 5 minutes on a duo core Macbook Pro, but you can keep the two switches and save a little time.

The next step is a bit odd. For some reason the rails and rake files don’t get installed as executable. You have to make them executable and then pick up the changes using the bash

1
hash

command.

1
2
3
chmod 775 $JRUBY_HOME/bin/rails<br />
chmod 775 $JRUBY_HOME/bin/rake<br />
hash -r

Sample Rails App Running in JRuby

Then create your test rails app in JRuby. I used that idea of a book store application:

1
2
rails bookstore<br />
cd bookstore

Go ahead and do a smoke test by booking up the server.

1
jruby script/server

Should see a default rails page at

  • http://localhost:3000

ActiveRecord JDBC Setup

Kill WEBrick and install the ActiveRecord JDBC gem:

1
2
3
4
gem install ActiveRecord-JDBC<br />
Installing ri documentation for ActiveRecord-JDBC-0.3.1...<br />
Installing RDoc documentation for ActiveRecord-JDBC-0.3.1...<br />
Successfully installed ActiveRecord-JDBC-0.3.1

Modify the

1
config/database.yml

:

1
2
3
4
5
6
development:<br />
  adapter: jdbc<br />
  driver: com.mysql.jdbc.Driver<br />
  url: jdbc:mysql://localhost/bookstore_development<br />
  username: root<br />
  password:

Modify

1
config/environment.rb

to add jdbc as an adapter type. The code goes just above

1
Rails::Initializer.run

[ruby]
if RUBY_PLATFORM =~ /java/
require ‘rubygems’
RAILS_CONNECTION_ADAPTERS = %w(jdbc)
end
Rails::Initializer.run do |config|
[/ruby]

Get the MYSQL JDBC driver at:

  • http://www.mysql.com/products/connector/j/

I grabbed the file

1
mysql-connector-java-5.0.6-bin.jar

and added it to my

1
$JRUBY_HOME/lib

. You can also add it to your

1
$CLASSPATH

instead.

Start your MySQL server if it isn’t running. I just do this from the MySQL Preferences pane.

Time to setup the databases:

1
2
3
4
mysql -u root<br />
create database bookstore_development;<br />
create database bookstore_test;<br />
exit

Go back to the rails app and create a model for Books.

1
jruby script/generate model Book

Create a simplistic migration script in the file

1
db/migrate/001_create_books.rb

:

[ruby]
def self.up
create_table :books do |table|
table.column :title, :string
table.column :author, :string
end
end
[/ruby]

Run the migration:

1
rake db:migrate

Then create the scaffolding for Book:

1
jruby script/generate scaffold Book<br />

Startup the server:

1
jruby script/server<br />

Go to the URL and see the scaffolding using JDBC:

  • http://localhost/books/

Running the Tests

You should be able to run the rake command and run all the tests now. Instead you get an error about like this:

1
2
rake aborted!<br />
Task not supported by 'jdbc'<br />

Turns out this is due to some hard coded values in the rails rake tasks. It has an easy fix by way of Ola Bini:

1
2
cd $JRUBY_HOME/lib/ruby/gems/1.8/gems/ActiveRecord-JDBC-0.3.1/lib<br />
svn checkout svn://rubyforge.org/var/svn/jruby-extras/trunk/activerecord-jdbc/lib/tasks<br />

This pulls down a file

1
jdbc_databases.rake

that I could only find in the subversion repository for now. Copy that file to the bookstore lib/tasks directory:

1
2
cp tasks/jdbc_databases.rake ~/jruby_stuff/bookstore/lib/tasks<br />
cd ~/jruby_stuff/bookstore<br />

Time to run all the default tests with rake:

1
rake<br />

All the tests pass!

Create the WAR

Kill WEBrick again and install the rails-integration plugin to deploy setup rake tasks to create wars:

1
jruby script/plugin install svn://rubyforge.org/var/svn/jruby-extras/trunk/rails-integration/plugins/goldspike<br />

It appears the war created uses the production settings so you’ll need to create the production database:

1
2
3
mysql -u root<br />
create database bookstore_production;<br />
exit<br />

Then fix the

1
config/database.yml

to include jdbc adapters for test and production:

1
2
3
4
5
6
test:<br />
  adapter: jdbc<br />
  driver: com.mysql.jdbc.Driver<br />
  url: jdbc:mysql://localhost/bookstore_test<br />
  username: root<br />
  password:<br />
1
2
3
4
5
6
production:<br />
  adapter: jdbc<br />
  driver: com.mysql.jdbc.Driver<br />
  url: jdbc:mysql://localhost/bookstore_production<br />
  username: root<br />
  password:<br />

Go ahead and run the migration for production as well:

1
rake db:migrate RAILS_ENV=production<br />

Then you run:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
rake war:standalone:create
<br />
Assembling web application<br />
  Adding Java library commons-pool-1.3<br />
  Adding Java library activation-1.1<br />
  Adding Java library jruby-complete-0.9.9<br />
  Adding Java library bcprov-jdk14-124<br />
  Adding Java library rails-integration-1.1.1<br />
  Adding web application<br />
  Adding Ruby gem rails version 1.2.3<br />
  Adding Ruby gem rake version 0.7.3<br />
  Adding Ruby gem activesupport version 1.4.2<br />
  Adding Ruby gem activerecord version 1.15.3<br />
  Adding Ruby gem actionpack version 1.13.3<br />
  Adding Ruby gem actionmailer version 1.3.3<br />
  Adding Ruby gem actionwebservice version 1.2.3<br />
  Adding Ruby gem ActiveRecord-JDBC version 0.3.1<br />
Creating web archive<br />

This may take a few minutes the first time, but it appears to be much faster in subsequent builds.

Deploy to Tomcat

At this point you just need to drop the mysql JDBC driver in TOMCAT’s lib directory at:

1
$TOMCAT_HOME/common/lib/mysql-connector-java-5.0.6-bin.jar<br />

Copy the bookstore.war file to

1
cp bookstore.war $TOMCAT_HOME/webapps/<br />

Then startup Tomcat:

1
$TOMCAT_HOME/bin/startup.sh<br />

Goto the app at:

  • http://localhost:8080/bookstore/books/

Now do your happy dance! Or maybe just take a break and grab a soda.

Sources

I got this recipe for deployment together from several sources:

Things To Come

  • Deploy a big rails app.
  • Deploy to a commercial container like Websphere Appliation Server.

9 comments to Deploying Rails to Tomcat as a WAR with JRuby

  • Ah, good writeup! The test issue with rake without arguments is caused by some hard coded values in Rails Rake tasks. To counteract, copy the file $JRUBY_HOME/lib/ruby/gems/1.8/gems/ActiveRecord-JDBC-0.3.1/lib/tasksjdbc_databases.rake
    into your railsapps lib/tasks-directory.

  • I added a section on how to get the rake test tasks running, thanks for the pointer. I did find a strange discrepancy though. The whole tasks/jdbc_databases.rake file and directory don’t show up when you install the ActiveRecord-JDBC gem.

    I looked in subversion and was able to find it tagged for the 0.3.1 release, but it doesn’t show up in the gem. I did an uninstall and reinstall and it still didn’t show up.

    You may need to rebuild the gem.

  • After running jruby script/generate model Book I got the following:

    ./script/../config/../config/environment.rb:15 warning: already initialized constant RAILS_CONNECTION_ADAPTERS
    /Users/shane/jruby-1.0/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:34:in `require’: no such file to load — active_record/connection_adapters/jdbc_adapter (MissingSourceFile)
    from /Users/shane/jruby-1.0/lib/ruby/gems/1.8/gems/rails-1.2.3/lib/commands/generate.rb:1
    from /Users/shane/jruby-1.0/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:32:in `require’
    from /Users/shane/jruby-1.0/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:32:in `require’
    from :-1

    Any ideas?

  • The error seems to be pointing that the ActiveRecord-JDBC gem isn’t there, but I’m guessing you’ve installed it. JRuby has gone up to a full release and ActiveRecord-JDBC is now at 0.4 instead of 0.3.1. I’ll try to set it up using the newer versions and see what results I get.

  • I got past point when I tried with JRuby 1.0 and ActiveRecord-JDBC 0.4 . But i did get a bug with the rails executable script in JRuby. I had to go in and change the rails script in JRUBY_HOME/bin to swap out the first line:

    #!/opt/jruby-1.0/bin/jruby

    change it to

    #!/usr/bin/env jruby

  • Thanks for the tips Ed. It turned out my problem was that I had another instance of gem in my path from a previous RoR install so the ActiveRecord-JDBC gem was installed there instead.

    One small editorial…the line above looks like it was fat-fingered:

    chmod 775 $JRUYB_HOME/bin/rake

    Thanks for the great tutorial!

  • Glad I could help. And I updated the little $JRUYB syntax error.

  • ——————————————————————-
    :::: Great Indian Developer Summit 2009 – GIDS.Java ::::
    :::: 24 April 2009 ::::
    :::: J N Tata Auditorium, IISc, Bangalore ::::
    :::: www .developersummit. com ::::
    ——————————————————————-

    Dear Group members,

    The economic downturn will run out of steam trying to outdo the ‘ready and waiting’ software professional. Packed with premium knowledge, action plans and advise from been-there-done-it veterans, creators, and visionaries, the 2009 edition of Great Indian Developer Summit features focused sessions, case studies, workshops and power panels that will transform you into a force to reckon with.

    Java Speakers at the 2009 edition of GIDS include: Clemens Utschig-Utschig, Craig McClanahan, Debu Panda, Frank Nimphius, Howard Lewis Ship, Dr. Jim Webber, Jonas Jacobi, Mike Keith, Ola Bini, Prabhu Sunderraman, Thomas Marrs and Venkat Subramaniam. The conference this year has sessions on Guerrilla SOA, REST, Groovy, Building Web Services Using Spring, Struts 2.0 Deep Dive, Computing in the Cloud, Building RESTful Applications with JAX-RS, Tuning performance of JPA Applications, Diagnosing Production Java Applications, Building RESTful Applications with Ruby on Rails, Maven 2 at Work, Apache Utilities at Work, Web Services at Work, JRuby, Testing Java with Ruby, Tapestry 5 Inversion of Control, Clojure: Concurrent Functional Programming for the JVM, Unit testing, Apache Tapestry 5 and much more. Please have a look at www .developersummit. com/speakers. html for more info on the speakers and the sessions.

    Register before the 29th of December for Rs. 1,999/-. Besides the learning at the GIDS.Java conference on Friday, the 24th of April, this fee also includes:

    1. Discount of 35% on the standard fee
    2. Assured Gift – GIDS 2009 Cult T-shirt (upon receipt of payment on or before Jan 12 2009)
    3. Entry into a lucky draw for the following gifts: Sony WEGA 29 inches (1), Mac Air Book (1), Wireless Mouse (50 nos), Apple iPOD 120 GB (5 nos).
    4. Lunch and refreshments
    5. Conference materials
    6. Complimentary invitation to Cyrus Broacha’s show at the Great Indian Developer Awards on Saturday, the 25th of April 2009

    So hurry up and register now under the GIDS Loyalty discount scheme: www .developersummit. com/registration. html

    Wishing you and your family a Merry Christmas and a wonderful year ahead.

    Thanks,
    Shaguf
    developersummit. com

  • [...] recorded first by jecharri on 2009-04-22→ Deploying Rails to Tomcat as a WAR with JRuby | Musings of a… [...]