Distinguish Ruby Runtimes with WhichRuby

Nowadays there are several decent Ruby runtimes available besides MRI ranging from alpha-versions to production-ready status. Using RVM these different interpreters become more and more interchangeable.

current problems

Since switching between runtimes became as easy rvm use x more care has to be taken to support a wide range of interpreters and versions. This is especially true for shared code like gems.

Some engines like JRuby have limitations that prevent the usage of some Ruby features. In most cases it’s possible to work around these limitations and provide a different solution that works, but might be somewhat less performant.

checking runtimes

Ruby is great at introspection, but especially 1.8 misses some key information like RUBY_ENGINE to determine the current interpreter at runtime and one has to extract it from the RUBY_DESCRIPTION constant.

WhichRuby aims at simplifying this tedious task and providing a simple API:

# [email protected]
jruby-1.4.0 > require 'which_ruby'
 => true 
jruby-1.4.0 > include WhichRuby
 => Object 
jruby-1.4.0 > jruby?
 => true

Executing different code fragments becomes as easy as defining a scope:

ruby_scope(:jruby) do
  # custom jruby code here
end

This comes in very handy for stuff like accessing Java code natively via JRuby instead of using RJB.

I don’t like Rubbae - I love it!

Ruby in Java, Java in Ruby, JRuby or Ruby Java Bridge?

Hosting (J)Rails applications on a high availability Java infrastructure with clusters, loadbalancers and all that shit stuff is great, if you already have it in place.

But does running an app on the JRE make it a JRuby application by default? Do you really want to be stuck on JRuby?

I really like the idea of running code with the most appropriate runtime available, that is why I use RVM all the time. JRuby is still very slow on startup and tools like autotest/autospec take minutes for just a handfull of tests…

So I would like to host Rails applications on a Tomcat, but on the other hand I want the tests to be executed with MRI! This should not be a problem as long as you don’t want to share a common codebase within Ruby and Java.

Integration

Is there a best practice for combining Java and Ruby?

Since every project is different, I think that you’ve got to evaluate the possible solutions to pick the one that fits best.

The next sections cover some approaches on integration of Java and Ruby code. Make sure to have RVM installed if you want to execute the provided example code. I assume that a JRE is provided with every OS nowadays…

Java in Ruby

There are two common solutions for embeding Java into a Ruby application. The first and obvious one is via JRuby, which can only be run with the JRuby runtime:

require 'java'

puts "access java.util.UUID via JRuby"
puts java.util.UUID.randomUUID().toString()
rvm use jruby 
=> Using jruby 1.5.0.RC1

jruby lib/jruby.rb 
=> access java.util.UUID via JRuby
=> a16fda6a-c57d-43b9-8376-801e48fe56b3

The same thing is possible using the Ruby Java Bridge from MRI:

require 'rjb'

puts "access java.util.UUID via RJB"
puts Rjb::import('java.util.UUID').randomUUID().toString()
rvm use 1.8.7
=> Using ruby 1.8.7 p249

ruby lib/rjb.rb 
=> access java.util.UUID via RJB
=> 1db8298c-5486-4933-be00-cdb180388e38

But it is also possible to do it the other way around!

Ruby in Java

Evaluating Ruby code in Java is dead simple with help of the JRuby library. You just need to set up a scripting container that executes your scripts:

  @Test
  public void execute_jruby_scriptlet() {
    new ScriptingContainer().runScriptlet("puts 'hello jruby world'");
  }

A more advanced example is to wire a Ruby class as a Spring bean. You need to provide some configuration and a Java interface that can be used as the basis for the bean:


<lang:jruby id="identifier" script-interfaces="de.nofail.Identifier" script-source="classpath:/ruby/identifier.rb">
    <lang:property name="uuid" value="#{ T(java.util.UUID).randomUUID().toString() }" />
</lang:jruby>
# identifier.rb
class Identifier
  def setUuid(uuid)
    @uuid = uuid
  end
  def getUuid()
    @uuid
  end
  def to_s()
    "Identifier[#{@uuid}]"
  end
end

# don't forget to return an instance as a bean
Identifier.new
// Identifier.java
public interface Identifier {
  String getUuid();
}
// SpringJRubyBeanTest.java
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "/applicationContext.xml")
public class SpringJRubyBeanTest {

  @Resource(name = "identifier")
  Identifier identifier;

  @Test
  public void generateUuid_success() {
    System.out.println("uuid: " + identifier);
  }
}

The code is currently not running with JRuby 1.5.0.RC1 so you need the latest stable release for testing.

checking Ruby enginges

It is even possible to mix and match all those approches! You just need to keep track of the Ruby engine that is evaluating your code. I created a little helper called which_ruby (available on rubygems) as a sidekick for this article, but more on that in the next week.

Some Ruby sugar in your cup of Java!

Migrating to Rails 3 for Heroku Bamboo

Recently there were some interesting updates to the Heroku infrastructure, giving the opportunity to migrate my personal Rails 2 website to Rails 3.

Having an app with only a single model for caching data, there is no worry about database migration. A nice opportunity for starting out new:

rvm use 1.9.1
gem install rails --pre
rails basement-rails3
cd basement-rails3
heroku create basement-rails3 --stack bamboo-mri-1.9.1

business as usual?

Not really… Having Yehuda Katz as a core developer of Rails 3, it’s no surprise they adopted the Merb approach of just using one executable for everything. So the ‘script’ folder now contains just a ‘rails’ script. Creating controllers, running the server, jumping into the console - all through the ‘rails’ command:

rails -h
=> [...]
=>  generate    Generate new code (short-cut alias: "g")
=>  console     Start the Rails console (short-cut alias: "c")
=>  server      Start the Rails server (short-cut alias: "s")
=> [...]

I appreciate the shortcuts! No more discussions about what shortcut to use for ‘script/server’ (ss is not an option in germany…)!

dependency management

Rails 3 has changed the way of working with gems. It uses bundler to deal with dependencies. Beeing a big fan of Java’s dependency management tools like Ivy or Maven, I think that separating out the dependency issue is good idea.

All dependencies are now defined in a separate ‘Gemfile’ using an easy dsl to manage the gems:

gem "rails", "3.0.0.beta"
[...]
gem "sqlite3-ruby", :require => "sqlite3"
[...]
group :test do
  gem "test-unit", "1.2.3"
end

I had some trouble getting bundler working on my machine, but after reinstalling Rails 3 AFTER the bundler gem, everything worked fine.

The only Rails plugin in my app is Haml and I was confident that it would play well with the latest Rails version. Never the less I was pleased to find RailsPlugins.org where one can check the compatibility of plugins with Rails 3.

escaping vs. html_safe

There were just very little changes to the existing codebase in my application. Despite one thing though, that forced changes to nearly all of the wrapper objects that are used to encapsulate the data that is coming from external services like twitter. The Problem is that Rails 3 has a strict way of dealing with escaping. Every string rendered into the view will be escaped unless it is ‘html_safe’. Since my application is using a lot of pregenerated content with inline html, adding ‘html_safe’ markers is inevitable:

  def content
    @json["content"]["$t"].html_safe
  end

Ruby 1.9 is different

The biggest pile of migration problems resulted from using Ruby 1.9.1. The latest Ruby version is a lot faster, but it has changed some of the core functionality. The ‘enum_with_index’ method for example is replaced with an ‘each_with_index’ method on a hash.
Using old YAML files resulted in some strange behavior as these files have changed format slightly (because of the new symbol style that Ruby 1.9 is using, I guess):

# old
  id: home
# new
  :id: home

Ruby 1.9 also changed the way of handling unicode characters. Using these in code forces the developer to put a magic comment in the first line of the ruby file:

# coding: utf-8
[...]

beta quirks

Most of the new Rails 3 stuff just works, but there are some reasons why it is still beta:

# rails console won't quit with controll-c but exits without error typing ö.ö
rails c
=> Loading development environment (Rails 3.0.0.beta)
ruby-1.9.1-p378 > ö.ö
^C

# rails help doesn't work for commands
rails -h
=> [...]
=> All commands can be run with -h for more information.
rails generate -h
=> Could not find generator -h.

Beta but running!

noSQL – Rails models with SOAP

Using a DB is a natural thing for a Rails developer. Since Rails is a database driven application framework, that does not come as a big surprise. But there are times where environmental constraints do not allow the freedom to use the weapon of choice…

Imagine a legacy Java SOA landscape that provides tons of webservices but does not permit access to a transaction DB. Sounds phoney? Ask your local J2EE consultant!

Working around this constraint, it would be great if one could just wire a SOAP service into Rails as a backing of model data. Using Rails without a database is a little bit tricky, especially if you don’t want to forego the power of ActiveRecord!

so why use Rails then?

There are a lot of people that would say “Why don’t you use Sinatra instead?”.

First of all, most Ruby developers know how to use Rails. The Rails community is large, lively and a great resource for knowledge. Features like REST come for free and nobody want’s to miss model validations. In general, Rails plugins are lazy programmers best friend!

working with ActiveForm

A simple way to get your SOAP backed noSQL model working with ActiveRecord::Validations is probably by using ActiveForm. It provides validations for non ActiveRecord models and is available on github.

You can install the Rails plugin via:

# (re)install from git as a plugin
script/plugin install --force git://github.com/remvee/active_form.git

Using the plugin in your code is simple. Inherit from ActiveForm instead of ActiveRecord::Base:

# app/models/blog.rb
class Blog < ActiveForm
  column :title
  column :message, :type => :text
  
  validates_presence_of :title, :message
  [...]
end

It’s possible to remove all evidence of database connectivity. Just kick ActiveRecord from the list of Rails frameworks and re-add it as a gem (this step is not necessary, so you might skip it and work with Rails sqlite3 default):

# config/environment.rb
Rails::Initializer.run do |config|
  [...]
  config.gem "activerecord", :version => '2.3.5'
  [...]
  config.frameworks -= [ :active_record, :active_resource, :action_mailer ]
  [...]
end

Doing so will allow you to delete the database.yml file in your application.

Savon for multi-tier persistence

Accessing an enterprise SOAP service with Savon is easy and integrating Savon into a Rails model requires just two steps:

  • implementing a to_hash method
  • implementing a save hook

Since Savon communication is based on data hashes, you have to provide a thin mapping layer to convert your model into a request hash that matches your SOAP interface:

# app/models/blog.rb
  def to_hash
    { :data => {:title=>title, :message=>message} }
  end

Pushing the data to the webservice requires some custom ‘persistence’ code to be implemented. A good place for that code should be in one of the model’s save hooks:

# app/models/blog.rb
  def after_save
    client = Savon::Client.new "http://localhost:8080/"

    client.post! do |soap|
      soap.namespace = "urn:savon:blog"
      soap.body = to_hash
    end
  end

Overwriting the after_save method is a neat way to let the model code be readable for other Rails developers. Sticking to conventions is a best practice and reduces complexity greatly!

more information?

There is a working example using a local soap4r server available on github.

no SQL - no problem!

Simple DB caching for Heroku

Heroku is a great platform. I like the style of the page, I appreciate the documentation and you can start up for free! One thing that I miss a lot is decent caching. The readonly filesystem eats up a lot of flexibility.

I played around with HTTP caching and Herokus Varnish works really well. The problem is that my app loads a lot of stuff from different 3rd party services like Twitter, so every new visitor will have all the load time on his first visit. Not a surprise that New Relic indicates that request times were ‘Unacceptable’…

I would like to check out the ‘Memcached Basic’ plugin of Heroku, but I did not manage to get into the private beta. So there was no other option than implementing a DB cache.

There is just one requirement that I have. Load stuff from a 3rd party service only if it’s expired. For simplicity, expired means, that the data is older than a predefined interval. In my test environment I like to use a shorter period than in production, so I define the interval in the environment files:

# config/environments/development.rb
CACHE_TIME = 30.seconds

# config/environments/production.rb
CACHE_TIME = 10.hours

A simple key-data pair is enough for my needs, because I always have a unique key for the values I want to cache. I am using Marshal.dump/Marshal.load for serialization, as they play well with anonymous inner classes that YAML can’t deal with. Encoding the data Base64 helps working around some SQLITE issues with serialized data strings:

# app/models/storage.rb
class Storage < ActiveRecord::Base
  
  validates_presence_of :key, :data
  
  def data=(data)
    write_attribute :data, ActiveSupport::Base64.encode64(Marshal.dump(data))
  end
  
  def data
    Marshal.load(ActiveSupport::Base64.decode64(read_attribute :data))
  end
  
end

The actual caching logic is embeded in my application controller. I provide a simple cache method, that can be called with a block. The block contains the remote call that I want to cache and is only executed if there is no data stored for the given key or the stored data is expired:

  # app/controllers/application_controller.rb
  def cache(key, &to_cache)
    from_db = Storage.first(:conditions => {:key => key})
    if from_db.nil? || from_db.updated_at < Time.new - CACHE_TIME
      data = (yield to_cache).collect{|t|t}
      return [] if data.nil? || data.empty?
      from_db = (from_db || Storage.new)
      from_db.key = key
      from_db.data = data
      from_db.save!
    end
    instance_variable_set :"@#{key.to_s}", from_db.data
  end

Finally the data is pushed into an instance varaible, so that I have access to it within my views.

Caching is now as simple as this:

  # cache all twitter posts and make them accessible via @tweets
  cache(:tweets){Helper::twitter_posts}

This little tweak noteable improved the response time of my app:

  This week:
  Apdex Score: 0.700.5 (Fair)

  Last week:
  Apdex Score: 0.060.5 (Unacceptable)

Sugar on rails!