and have a Ruby version running side-by-side.
A few months ago I got interested in JRuby while researching for text mining algorithms. I found some gems but they are either unmaintained or inadequate while the mature libraries I found were written in Java. No problem! JRuby to the rescue. Thank God.
Next stop, I decided to take Rails 3 and JRuby for a spin. Incidentally, I will be on a 3-city Rails tour in the Philippines this September and since there are many Filipino Java developers, they might find it interesting to see their favorite Java platform works nicely with Ruby on Rails.
Setup
I will be using the following for this tutorial:
java 1.6 + JDK
tomcat 7.0.2
rvm 1.0.1
jruby 1.5.0
ruby 1.9.2p0
Further below, I outline how to install these software. First, let’s see my current environment.
$ more /etc/issue Ubuntu 9.10 \n \l $ java -version java version "1.6.0_20" Java(TM) SE Runtime Environment (build 1.6.0_20-b02) Java HotSpot(TM) Server VM (build 16.3-b01, mixed mode) $ rvm -v rvm 1.0.1 by Wayne E. Seguin (wayneeseguin@gmail.com) [http://rvm.beginrescueend.com/] $ jruby -v jruby 1.5.0 (ruby 1.8.7 patchlevel 249) (2010-05-12 6769999) (Java HotSpot(TM) Client VM 1.6.0_20) [i386-java] $ TOMCAT/bin/version.sh Using CATALINA_BASE: /usr/local/apache-tomcat-7.0.2 Using CATALINA_HOME: /usr/local/apache-tomcat-7.0.2 Using CATALINA_TMPDIR: /usr/local/apache-tomcat-7.0.2/temp Using JRE_HOME: /usr Using CLASSPATH: /usr/local/apache-tomcat-7.0.2/bin/bootstrap.jar:/usr/local/apache-tomcat-7.0.2/bin/tomcat-juli.jar Server version: Apache Tomcat/7.0.2 Server built: Aug 4 2010 12:23:47 Server number: 7.0.2.0 OS Name: Linux OS Version: 2.6.31-22-generic Architecture: i386 JVM Version: 1.6.0_20-b02 JVM Vendor: Sun Microsystems Inc. $ ruby -v ruby 1.9.2p0 (2010-08-18 revision 29036) [i686-linux] # install jdk and tomcat $ aptitude install curl sun-java6-bin sun-java6-jre sun-java6-jdk $ wget http://apache.mobiles5.com/tomcat/tomcat-7/v7.0.2-beta/bin/apache-tomcat-7.0.2.tar.gz $ tar zxvf apache-tomcat-7.0.2.tar.gz $ mv apache-tomcat-7.0.2 /usr/local
Of course, these assume you want to use 7.0.2 and you want it installed at your /usr/local.
Install JRuby, Rails 3
I assume you already have rvm installed. If not, I highly recommend that you do. I can’t imagine a Ruby developer not using rvm 🙂
$ rvm install jruby $ rvm jruby $ rvm gemset create railsjam $ rvm jruby@railsjam $ gem install rails
Try a sample app
I’ve created sample app for the RailsJam tour. This have several functionalities already and better than creating a Rails app from scratch.
$ git clone git://github.com/gregmoreno/railsjam.git
Update the Gemfile
You need a separate set of gems to make your Rails 3 application work with JRuby. For learning purposes, I want my Rails 3 application to work other than JRuby. To accomplish that, we need to specify what gems are needed solely by JRuby.
source 'http://rubygems.org' gem 'rails', '3.0.0' if defined?(JRUBY_VERSION) gem 'jdbc-sqlite3' gem 'activerecord-jdbc-adapter' gem 'activerecord-jdbcsqlite3-adapter' gem 'jruby-openssl' gem 'jruby-rack' gem 'warbler' else gem 'sqlite3-ruby', :require => 'sqlite3' end
(A copy of this Gemfile is available at the ‘jruby’ folder of the railsjam application.)
Now, it’s time to intall the gems. You must delete ‘Gemfile.lock’. Otherwise, bundle picks up wrong version of jdbc
$ rm Gemfile.lock $ jruby -S bundle install
Prepare the database.
The first time I worked on this tutorial, I needed to specify the jdbcsqlite3 as the database adapter. However, when I tried the tutorial on the same machine with a fresh gemset, it worked pretty well with just ‘sqlite3’. Just to be sure, I modified ‘database.yml’ to check for JRuby.
development: adapter: <%= defined?(JRUBY_VERSION) ? 'jdbcsqlite3' : 'sqlite3' %> database: db/development.sqlite3 pool: 5 timeout: 5000 production: adapter: <%= defined?(JRUBY_VERSION) ? 'jdbcsqlite3' : 'sqlite3' %> database: /home/greg/dev/railsjam/db/development.sqlite3 pool: 5 timeout: 5000
When you deploy to Tomcat, it will be on ‘production’ mode by default. Since sqlite3 is file based and for simplicity, I used the same development database.
Now, do the migration.
$ jruby -S rake db:migrate
Deploy to Tomcat
We use ‘warble’ which is an excellent tool for packaging your Rails application. It packages everything you need to run your Rails application inside a Java container.
$ warble $ cp railsjam.war $TOMCAT/webapps # start Tomcat # assuming you arein $TOMCAT dir $ sudo ./startup.sh
Check your Rails 3 application
# You should see the famous Rails welcome localhost:3000/railsjam # Play around with your application localhost:3000/railsjam/users
Deploy Rails 3 using Ruby 1.9.2
Without shutting down your JRuby and Tomcat version, let’s try to run our app using Ruby 1.9.2
# In a new console $ rvm 1.9.2 $ rvm gemset create railsjam $ rvm 1.9.2@railsjam $ gem install rails # Assuming you are in the ‘railsjam’ folder # This will install sqlite3-ruby gem $ bundle install $ rails server Now, go play with your Rails 3 applications # jruby + tomcat http://localhost:8080/railsjam/users # ruby 1.9.2 http://localhost:3000/users
In case you encountered some problems, here are some ways to solve them. If your problem is not listed here, you can email me. I only accept Paypal 🙂
JRuby does not support native extensions
You did not update the Gemfile to use the jdbc version of sqlite3. You will encounter this error when you install the gems.
$ bundle install .... Installing sqlite3-ruby (1.3.1) with native extensions /home/greg/.rvm/rubies/jruby-1.5.2/lib/ruby/site_ruby/1.8/rubygems/installer.rb:482:in `build_extensions': ERROR: Failed to build gem native extension. (Gem::Installer::ExtensionBuildError) /home/greg/.rvm/rubies/jruby-1.5.2/bin/jruby extconf.rb WARNING: JRuby does not support native extensions or the `mkmf' library. Check http://kenai.com/projects/jruby/pages/Home for alternatives. extconf.rb:9: undefined method `dir_config' for main:Object (NoMethodError)
undefined method `attributes_with_quotes’ for class `ActiveRecord::Base’
I first encountered this problem when doing migration.
$ rake db:migrate rake aborted! undefined method 'attributes_with_quotes' for class 'ActiveRecord::Base'
This is caused by an old version of your jdbc gems. In my case, sometimes bundler installs the old versions:
Installing activerecord-jdbc-adapter (0.9.2) Installing activerecord-jdbcsqlite3-adapter (0.9.2)
As of this writing, the latest version is 0.9.7
Installing activerecord-jdbc-adapter-0.9.7-java Installing activerecord-jdbcsqlite3-adapter-0.9.7-java
Bundler keeps installing 0.9.2
$ rm Gemfile.lock $ jruby -S bundle install
no such file to load — sqlite3
$ rake db:migrate (in /home/greg/dev/projects/jruby/railsjam) rake aborted! no such file to load -- sqlite3
‘sqlite3’ is the default name of the database adapter but with jruby, it should be ‘jdbcsqlite3’.
But, when I tried ‘sqlite3’ with a fresh gemset and a new machine, it went well.
Anyway, just in case you run into the same problem in the future, add a condition
in your database.yml
development: adapter: <%= defined?(JRUBY_VERSION) ? 'jdbcsqlite3' : 'sqlite3' %> database: db/development.sqlite3 pool: 5 timeout: 5000 production: adapter: <%= defined?(JRUBY_VERSION) ? 'jdbcsqlite3' : 'sqlite3' %> database: /home/greg/dev/railsjam/db/development.sqlite3 pool: 5 timeout: 5000
We’re sorry, but something went wrong.
If you see the famous Rails error message, you need to dig in Tomcat’s log files.
$ cd /usr/local/apache-tomcat-7.0.2/logs $ ls -al localhost* -rw-r--r-- 1 root root 1181 2010-09-01 00:17 localhost.2010-09-01.log -rw-r--r-- 1 root root 1062 2010-09-01 00:18 localhost_access_log.2010-09-01.txt $ tail -f localhost.2010-09-01.log
In the log file, you will see the errors like missing database.
org.jruby.rack.RackInitializationException: The driver encountered an error: java.sql.SQLException: path to '/home/greg/dev/tmp/apache-tomcat-7.0.2/webapps/railsjam/WEB-INF/db/production.sqlite3': '/home/greg/dev/tmp/apache-tomcat-7.0.2/webapps/railsjam/WEB-INF/db' does not exist