Archive for 2007

Rails WAR with a Tomcat

{Monday, March 5th, 2007}

Want to deploy a Rails app WAR on an application server and confused how to go about it? In this blog I’ll summarise how you can create a WAR. This information is ‘out there’ but so disjointed you’ll rightly give-up before you try, to make matters worse it’s usually specific to GlassFish.

Here I’ll focus on deploying to Tomcat using Java 5.

Download JRuby

In my case I checked out the trunk although using 0.9.2 may be an option. Note that you’ll need to perform a couple of modifications if you intend on using JRuby as a substitute for Ruby:

  • Add rake.bat to the bin directory. I quickly threw one together based on gem.bat. Note that there are issues executing rake from the bin directory.
  • Place JRuby’s bin directory before Ruby’s bin on your OS path
  • Install all of your dependent gem’s in JRuby. Logically the ‘JRuby Way’ is identical to Rubys, gem install

If you need to create the JRuby jar, ant jar constructs jruby.jar in the lib directory.

I had an issue successfully executing the tests, the ANT jar provided in the lib directory appeared to be incorrect (org.apache.tools.ant.util.FileUtils.close(Writer) was not found). Replacing this jar with the latest solved the problem.

Download Rails-Integration

Rails-Integration is part of the JRuby Extras project. Unfortunately, it hasn’t been released yet so you’ve no alternative but to grab the package off the trunk.
Rails-Integration has two key parts:

  1. Servlets that create a Ruby Runtime and delegate to the Rails dispatcher
  2. Rake tasks used to compose a Rails application WAR

You’ll need to use ANT to JAR-up those servlets: ant jar should do the trick.
Note that the jar task causes tests to execute which will probably initially fail and kill JAR creation. You’ve a few options here:

  • Alter the build so that tests are not run
  • Correct the failing tests

I ended up taking the latter option to ensure that my snapshot was legitimate. After tweaking with library dependencies I managed to get green lights here.

Download Active-Record JDBC integration

  1. Install the ActiveRecord-JDBC integration library in JRuby, gem install ActiveRecord-JDBC should do the trick
  2. Add the following to environment.rb before Rails::Initializer.run do |config|:
    if RUBY_PLATFORM =~ /java/
        require 'rubygems'
        RAILS_CONNECTION_ADAPTERS = %w(jdbc)
    end
    
  3. Change database.yml to use JDBC for connection management. Something like the following:
    adapter: jdbc
    driver: com.mysql.jdbc.Driver
    url: jdbc:mysql://<host>/<database>
    username : <username>
    password: <password>
    

Customise Rails

As all of this stuff is experimental (some pre-release, all pre-version 1.0) nothing comes easy. You’ve some tweaking to do. The Rails libraries dispatcher.rb can’t be interpreted correctly by JRuby at the time of writing.
I needed to comment out all lines pertaining to breakpoints as the constant BREAKPOINT_SERVER_PORT (a constant unassociated with a module) could not be interpreted. This is not so bad given Breakpoint/Debug Driven Development should be discouraged.

Create WAR

There are 2 packaging strategies for your Rails application:

  • Dependent gems bundled in the WAR
  • Access dependent gems by configuring JRuby’s home directory

I preferred the latter as it significantly reduces the WAR’s payload, but the foremost option is reasonable in cases where you’d like to drop the WAR and run.

Here’s the key steps to create the WAR:

  1. Copy the Rails-Integration war plugin to your Rails application root directory
  2. Alter the plugins war_config.rb, specifying all dependent JAR’s. All JAR’s are expected to be located in your Maven repository by default. Note that JRuby appears to hijack classloading such that it can only resolve classes via the applications classloader, bypassing the server classloader for some reason unknown to me. For Tomcat, this lead to failures in loading Tomcat specific classes. To quickly remedy this I included catalina.jar in the WAR. You’ll also need to include a jar containing your JDBC driver.
  3. (Bundle option only) Alter the plugins war_config.rb to specify all dependent gem’s
  4. All your Rails applications directories will be archived in the WAR by default, to reduce the payload alter the plugins packer.rb WebappPacker class to filter out directories such as test and doc
  5. Create a dependent WAR using rake create_war:standalone or rake create_war:shared to exclude dependent gems

If you’ve followed to this point you should have a WAR in your Rails applications root directory. Drop it in your app server and cross your fingers!

Tip: You should also be able to jruby script\server your application to life via WEBrick, this can be useful to iron out configuration issues.

Related information:
JRuby on Rails
Rails on Glassfish
Rails with ActiveRecord JDBC

Why Ruby on Rails Now?

{Thursday, March 1st, 2007}

A while ago I chuckled at this comparison of Java web app vs Rails app books.

That Rails pile has grown a year or so later. Now it’s looking something more like this…

PickAxe
Agile Web Development with Rails
The Ruby Way
Rails Recipies
Rails for Java Developers
Pragmatic Ajax
Enterprise Integration with Ruby
Mastering Regular Expressions

And the list grows…

Pondering Rails WAR’s

{Thursday, March 1st, 2007}

For organizations developing and deploying Rails apps in house, does the prospect of deploying Rails apps as a WAR give you that much? Consider this…

  • JRuby’s performance is well below conventional Ruby (although inroads are being made)
  • JRuby is yet to reach 1.0. Not all Rails features are supported
  • Composing and successfully deploying a WAR is not for the faint-hearted, errors and poor documentation abound

And what say you Java shops considering adopting Rails, does this capability really effect your decision? Does it make the prospect of learning a new language and a ream of frameworks and plugins any prettier?

For those convinced of the Rails cool-aid (and why shouldn’t you be anyway?!), it’s neat seeing a Rails app run in the snug, familiar confides of Tomcat and alike - even if it does chug along a tad. It certainly brings into perspective the gains of using the JVM as a VM for other languages – those languages inherit its benefits.