Deploy a Rails 3, Sqlite3 application in Tomcat using JRuby

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
Tagged , ,

8 thoughts on “Deploy a Rails 3, Sqlite3 application in Tomcat using JRuby

  1. Anonymous says:

    AFAIK java/j2ee servlet-containers don’t provide file-system persistence so my question is how will SQLite3 write to a file under WEB-INF/db/production.sqlite3 ???

    Moreover if your database resides in WEB-INF/db then a redeploy will wipe the previous state unless ofcourse you download the database and repackage into a war prior to redeploy. I would like to know how you manage not to loose your data.

  2. foobar says:

    Very good points by anonymous, I’d also like to see some suggested solutions to these.

  3. petdeal says:

    warbler does not properly package certain gem files such as calendar_date_select. Use Glassfish3 or webrick, avoid war files as they do not get properly bundled by warbler and therefore do not get deployed correctly to Tomcat………..

  4. I personally Feel post, “Deploy a Rails 3, Sqlite3 application in Tomcat using JRuby | Greg Moreno” was indeed fantastic!
    I personallycan’t agree together with u more! At last appears like I personallystumbled upon a blog page truly worth looking through. Thanks for the post, Clint

  5. daviddefco says:

    Hi,

    Thanks for the tutorial. It is very good indeed. However, I can’t get my app running. I followed all the steps, use warble and get the war, which I deploy in Tomcat. When I try to acess the app I get this error trace:

    org.jruby.exceptions.RaiseException: (LoadError) Please install the jdbcsqlite3 adapter: `gem install activerecord-jdbcsqlite3-adapter` (no such file to load — active_record/connection_adapters/jdbcsqlite3_adapter)

    I have the dependency defined in the Gemfile as in your example, and the result of the bundle install shows the gem, which is already installed. I have also chenged the YAM file as suggested. In the Tomcat logs I don’t see the gem in the LOAD_PATH, so it seems warble does not include the gem in the WAR.

    Any idea about why this happened and how to solve it?

    Thanks for the help!

  6. daviddefco says:

    Hi again,

    Just found out my activerecord-jdbcsqlite3-adapter dependency was only defined in the :development group.As you say in the tutorial, Tomcat deployment is made in the :production environment. Defining the dependencies in the right environment solved the problem and your tutorial worked for me.

    Thanks again for the tutorial.

  7. Benito says:

    I Believe that blog post, “Deploy a Rails 3, Sqlite3 application in Tomcat using JRuby
    | Greg Moreno” fishermensmonument was indeed perfect!
    I personallycouldn’t see eye to eye together with u even more! Finally looks like I personallyidentified a blog page worthy of reading through. Thanks for your time, Brian

  8. Just copying the generated WAR was not enough, I think. I copy-pasted the war in TOMCAT_HOME/webapp folder, restarted Tomcat, tried to navigate to localhost:8080/blog. (blog is the name of my rails app) and got the below error:

    ActionView::Template::Error (ActiveRecord::JDBCError: [SQLITE_ERROR] SQL error or missing database (no such table: posts): SELECT “posts”.* FROM “posts”):

    It seems like Tomcat daoe not see my production.sql3 file; Any idea how to fix that ? I have:

    jruby 1.7.10 (1.9.3p392)
    rails 4.0.2
    activerecord-jdbcsqlite3-adapter (1.3.6, 1.3.0.beta1

    Thanks

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: