dcsimg

Rails vs. Grails vs. Helma: The JVM Web Framework Smackdown, Part 1

It's the ultimate JVM Web Framework Smackdown! Three will enter the cage. Only one will exit the victor. Will it be JRuby on Rails? Groovy on Grails? Or Helma?

Rails Scaffolding and Pagination

Once upon a time, Rails shipped with built-in features for dynamic scaffolding and pagination. These have been removed from the core framework in favor of separate plugins.

The removal of dynamic scaffolding is perhaps understandable—the dynamic scaffolding pages usually needed to be replaced anyway. Scaffolds are now created through the generate script. However, the loss of pagination is a little more disappointing. Although there are multiple pagination plugins available, the stock, generated controller and views do not use them. However, it is easy enough to integrate a plugin.

Rails’s non-dynamic generated scaffolding is an incredibly nice feature. It allows you to set up a useful data entry tool in virtually no time at all. However, Rails controllers for scaffolds assume that every action takes an ID field. You might have noticed the extraneous id=>0 in some of the code snippets. Without it, you are given an error.

ActiveRecord::RecordNotFound in UsersController#show
  Couldn't find User with ID=login
  ...

There are ways around this problem. The easiest is simply to use a different controller for those actions. You can also attempt to edit config/routes.rb. Passing a fake ID is probably the ugliest approach, but it works.

Integrating JRuby on Rails with Java

One of the benefits of JRuby is that, in addition to Java’s libraries, you have most of Ruby’s available as well. These include most libraries written in pure Ruby, and also those written in C that the JRuby team has ported over.

In the case of PenguinMusic, no Java library is required, but let’s pretend otherwise. How hard is it to integrate a Java library? Let’s replace the use of Ruby’s MD5 library with a call to a Java library. Java’s implementation is a little more complex, but a wrapper hides much of the detail. Here’s lib/utils/hash.rb:

require 'java'
  include_class 'java.security.MessageDigest'
  include_class('java.lang.String') {|package,name"J#{name}" }
  include_class('java.math.BigInteger') {|package,name"J#{name}" }

  module Utils
    class Hash
      def (Utils::Hash).md5sum(s)
        s = JString.new(s)
        m = MessageDigest.getInstance(JString.new "MD5")
        m.update(s.bytes, 0, s.length)
        JBigInteger.new(1, m.digest).toString(16)
      end
    end
  end

Interacting with Java in JRuby is a little more complex than with the other languages, but not horribly so. The primary complication in the code above comes from the String class. Since JRuby does not use Java’s String class and is more strict about conversions, you must wrap any Strings passed to Java methods in a JString object.

Testing

Given the new hash function, it would be nice to test it. Testing is one of Rails’s real strengths. Rails generates testing classes and includes rake targets to run your tests automatically. Let’s hash a few different words to see if any problems crop up:

require 'test_helper'

class UserTest < ActiveSupport::TestCase
  test "hash function" do
    assert_equal "fe01d67a002dfa0f3ac084298142eccd", Utils::Hash.md5sum("orange")
    assert_equal "72b302bf297a228a75730123efef7c41", Utils::Hash.md5sum("banana")
    assert_equal "c7a4476fc64b75ead800da9ea2b7d072", Utils::Hash.md5sum("cherry")
    assert_equal "9dee45a24efffc78483a02cfcfd83433", Utils::Hash.md5sum("pineapple")
    assert_equal "3f24e567591e9cbab2a7d2f1f748a1d4", Utils::Hash.md5sum("lemon")
    assert_equal "67c0ecaf5a1b782b11146e9fbe80f016", Utils::Hash.md5sum("lime")
    assert_equal "aa00faf97d042c13a59da4d27eb32358", Utils::Hash.md5sum("mango")
    assert_equal "027086dff18471311f7816dba7f92909", Utils::Hash.md5sum("artichoke")
  end
end

When the tests run, the test for artichoke fails:

1) Failure:
test_hash_function(UserTest) [test/unit/user_test.rb:17]:
<"027086dff18471311f7816dba7f92909"> expected but was
<"27086dff18471311f7816dba7f92909">.

Oops. The function is dropping the leading 0. A slight change fixes the problem:

      ...
      m.update(s.bytes, 0, s.length)
      hashVal = JBigInteger.new(1, m.digest).toString(16)
      format('%32.32s', hashVal.to_s).gsub /\s/, '0'
      ...

This really just scratches the surface of the testing tools Rails offers. Rails makes it so easy to get started, even giving you a few basic functional tests to begin with.

Is JRuby Worth It?

At this point, hardened Rails developers might well wonder if JRuby on Rails really offers any tangible benefits. If you do not need any of Java’s libraries, is it really worth the additional hassle and complexity?

There is a trade-off. If you choose JRuby as your implementation, you gain a little extra hassle, and you may run into problems that no one else has faced. You also give up continuations. On the other hand, you gain a superior threading model and better support for Unicode, though for the latter you need to use Java’s String class instead of Ruby’s. Deployment may arguably be a little simpler—using Warbler, you can deploy your JRoR application as a standard WAR file. You also, of course, gain access to the cornucopia of Java tools and libraries.

The Final Word on JRoR

Ruby on Rails has set the bar for Web development. The exciting thing about JRoR is that it feels no different from Rails development. At the same time it’s a little disappointing that JRoR is, well, no different than Rails development.

While Ola Bini and others have highlighted some ways that different Java components could be used, it would be nice to have a couple of extra features to help distinguish JRoR from Rails. Of course, the issue is that there is no JRoR team. There is the JRuby team, and the Rails team.

But in the end, JRoR works as well as advertised. For those who already have some expertise with Rails and wish to take advantage of Java libraries, JRoR is probably the best option.

The Good

  • Robust framework, with a rich set of Ruby libraries in addition to Java libraries
  • Easy learning curve for those who already know Ruby on Rails
  • Excellent tools for testing

The Bad

  • Views quickly become littered with code
  • Essentially a Ruby framework — does not leverage Java tools.

Check back for Part 2 where we tackle Grails!

Fatal error: Call to undefined function aa_author_bios() in /opt/apache/dms/b2b/linux-mag.com/site/www/htdocs/wp-content/themes/linuxmag/single.php on line 62