JRuby on Rails running in Apache Tomcat

I tried JRuby for the first time in small project listed in my previous blog entry. While I wouldn’t say it’s love at first sight (or first use), it intrigued me sufficiently to try out other usages of JRuby.

What is JRuby? If you just think it this way — the Ruby that you and I know and love is a C implementation of the Ruby programming language — then JRuby is quite easy to understand. JRuby is the Java implementation of the Ruby programming language.

What the major difference and advantage in JRuby is that you’ll be able to define and interact with Java classes in Ruby directly. And that’s it. It’s not really different from Ruby, except that some built-in classes are not supported. And if you look at it from another angle, it’s not really that different between doing it this way (using JRuby) and using WIN32API or WIN32OLE, except of course you’ll need to know all the Java nuances and quirks.

Enter JRuby on Rails. Why JRuby on Rails? I think anyone who has done Java and Rails would be able to answer this one. It’s simply the vast ocean of Java libraries available, both good and bad, that gives JRuby on Rails the appeal for me. No doubt, the ‘enterprise’ factor of Java EE (i.e. running on a Java EE app server like Glassfish or the likes) is pretty appealing to those who care but I would say it’s not really worth it (at least at this point in time).

I was quite impressed with the demos done with JRuby and Glassfishv2 during JavaOne so I thought to give it a run to see what happens. The results are not too bad, although not everything works smoothly. For the current status of Rails support in JRuby click here.

Let me run through quickly how you can deploy a JRuby on Rails application on Apache Tomcat 6. Why Tomcat? While there are a growing number of Java EE application servers out there, Tomcat is probably the one that most Java EE programmers cut their teeth and is most familiar with.

1. You’ll need to install JRuby. Installation is quite easy, just download the latest package from http://dist.codehaus.org/jruby/ and then unzip it into any directory.
2. Now set the environment variable JRUBY_HOME to point to this directory and set your path to point to JRUBY_HOME/bin. If you’re doing this all the time you should set this permanently.
3. Now quickly test your JRuby installation by typing ‘jirb’ on your console and then the following:

$ jirb
irb(main):001:0> require 'java'
irb(main):002:0> frame = javax.swing.JFrame.new "JRuby Frame"
irb(main):003:0> frame.add "Center", button
irb(main):004:0> frame.setVisible true
irb(main):004:0> frame.setSize 200,100

4. You’ll notice that the frame is resized dynamically
5. Now you’ll need to install the Rails gems. Go to JRUBY_HOME/bin and run this command:

$ jruby gem install rails

JRuby will automatically install the necessary rails gems.

6. You’ll need to install the ActiveRecord-JDBC gem as well

$ jruby gem install activerecord-jdbc

7. Now, you can create or take your existing rails application and add the Rails-Integration plugin.

$ rails JRubyRailsTest
$ cd JRubyRailsTest
$ script/plugin install svn://rubyforge.org/var/svn/jruby-extras/trunk/rails-integration/plugins/goldspike

8. Check the rake tasks available now, you should have a couple of new rake tasks that starts with war:

$ rake –tasks
rake tmp:war:clear             # Clears all files used in the creation of a war
rake war:shared:create         # Create a war for use on a Java server where JRuby is available
rake war:standalone:create     # Create a self-contained Java war
rake war:standalone:run        # Run the webapp in Jetty

The tasks are pretty self explanatory.

9. There are a couple of things you need to change in the Rails configuration itself to enable Rails to run properly under a Java EE application server so you need to go into the config directory now.
10. Open up environment.rb and add these couple of lines in :

if RUBY_PLATFORM =~ /java/
  require 'rubygems'

This should come just before

Rails::Initializer.run do |config|

This will enable you to use ActiveRecord-JDBC. There are a couple of configurations given on other tutorials but this is the one that works for me.

11. Now open up database.yml to configure the database connection.

development:adapter: jdbc
 driver: com.mysql.jdbc.Driver
 url: jdbc:mysql://localhost:3306/<myDevelopmentDatabase>
 username: <username>
 password: <password>

 adapter: jdbc
 driver: com.mysql.jdbc.Driver
 url: jdbc:mysql://localhost:3306/<myProductionDatabase>
 username: <username>
 password: <password>

Remember to change both the development and production. You can point them to the same database, but right now, the Rails-Integration will redirect to the production database once you archive your application into a WAR. In this example, I’m using MySQL but you can use any JDBC URL to connect to any JDBC enabled database.

12. If you’re doing a new application, and you want to generate some code, remember to use JRuby and not the normal Ruby interpreter. For example, to create a scaffold for User (assuming you have done all the necessary table creation in your database of choice)

$ jruby script/generate scaffold User

If you can’t generate, go back and check out steps 9 – 11. Also to note is that you’re running Java as well, so check your classpath if you are missing the JDBC drivers for your database.

13. For instant gratification, run WEBrick on JRuby:

$ jruby script/server

And try it out quickly to ensure it works.

14. Onwards to make it work for a Java EE application server! First, you’ll need to add in any libraries you need into the Rails-Integration configuration, so that it’ll include that library when it builds the WAR file. Go to <your Rails application>/vendor/plugins/goldspike/lib/war_config.rb and add in your libraries. For example, to use MySQL, you’ll need to put in the MySQL drivers like this:

add_library(maven_library ('mysql', 'mysql-connector-java', '5.0.4'))

Browse around the code until you find a place to put this line.

15. We’re almost there. Run the rake task in your Rails application folder to create the WAR file:

$ JRUBY_HOME/bin/jruby JRUBY_HOME/bin/rake war:standalone:create

This will create the WAR file by archiving your code and any libraries needed to run JRuby. The first time you run it might take a while and you’ll need to be connected to the Internet in order for Maven to bring in the Java libraries from its public repository but subsequently it’ll be much faster. A problem I faced earlier on is that while getting some libraries, the connection will expire and creation is aborted. I had to run it a few times before it completes properly.

16. You’re done! You now have a WAR file that wil run on Tomcat 6 or Glassfishv2 (I tried both). Just deploy them normally as you would any web application.