Underneath DataMapper (at least if you haven't bitten the NoSQL bullet just yet) lies DataObjects. DataObjects is an attempt to rewrite existing Ruby database drivers to conform to one, standard interface. If you're a recent arrival from the world of PHP or .Net, then the DO API will not look too disimilar to either PDO or ADO.net.
Late this spring, tucked away in the DataObjects' Release Notes for version 0.9.12, was mention of support for JRuby. Unfortunately the support that featured in 0.9.12 was incomplete at best. We needed a little longer to get things working well, but over the summer we made significant progress in supporting a large number of databases on the JRuby platform.
For a long while, I had a Gist up on Github illustrating the steps needed to get up and running with DataMapper on JRuby. I promised to follow up with a more detailed tutorial, but it's taken some time to get it published. In part, this has been down to the fact that going through the process of writing a tutorial has helped me uncover a plethora of bugs and inconsistencies, and I wanted to take the time to deal with them before hitting the metaphorical "publish" button. In any case, I hope this will be the first of many future Ruby postings.
For the purposes of this tutorial, I am using Merb as the MVC Framework, but you should also be able to use Rails, Camping, or Sinatra.
Install Java and the JDK
If you are running a recent version of Mac OS X, you should already have both the Java Runtime Environment and Java Development Kit (JDK). Apple supplies their own set of Java tools (although the Soylatte implementation is available if you want Java 6 on Tiger and Leopard 32-bit machines).
On Windows or a Linux distribution, you will likely already have the Java Runtime Environment, but unless you've been doing Java development, you may be without the JDK. The JDK is available from Sun's Java downloads page.
We generally test against the latest stable version of JRuby. I've also tested
against v1.2.0, but I'd recommend being on 1.3.1 or 1.4.0. Installing JRuby
is as simple as downloading and decompressing the distributed
file (or running the new
.exe installer, if you're on Windows).
Verbose installation instructions for JRuby are now available on the Data Objects' wiki.
Configure your Path
Firstly, make sure JRuby is in your PATH. Typing
jruby --version should give
print out the version:
$ jruby --version jruby 1.4.0RC2 (ruby 1.8.7 patchlevel 174) (2009-10-21 7e77f32) (Java HotSpot(TM) Client VM 1.6.0_15) [i386-java]
Because these instructions rely on installation from source, we'll also be
compiling extensions that are written in Java. Hence make sure the JDK (and the
javac) are in your PATH:
c:\Users\alexbcoles>javac -version javac 1.6.0_16
On Windows for example, this would mean adding
to PATH. Again, more verbose instructions can be found in the wiki.
Install DataMapper + Merb
A major requirement in developing DataObjects'/DataMapper's JDBC support was parity in the installation procedure. Installing on JRuby should be just as easy as for MRI / 1.9.
The good news is that if you want the latest published gems, you should be able to install them as follows:
jruby -S gem install do_sqlite3 dm-core dm-more merb
That's it! Unlike with ActiveRecord, you don't have to specify a separate JDBC variant.
However, for the purpose of these instructions and because our JRuby support is still developing at a rapid pace (for instance, our SQL Server support is only available in our Git repository), we'll cover installing the edge version of DataObjects / DataMapper.
Note: Under Windows Vista/7, if you've used the JRuby installer and have
your system gems directory in
C:\Program Files\ then you may have to run
cmd.exe with Administrator privileges (Start -> type
click, Run as Administrator).
Note: On *NIX platforms, you may need to prefix commands with sudo,
depending on where you installed
jruby (unless, of course, you're using
Install Addressable and an implementation of JSON:
jruby -S gem install json_pure addressable
Install Jeweler (DataMapper and Merb projects are currently in the process of migrating their Rakefiles to use Jeweler):
jruby -S gem install jeweler
Change to the directory where you keep your Code. (So
c:\Documents and Settings\harry\Code, etc.)
We start by installing Extlib:
git clone git://github.com/datamapper/extlib.git cd extlib jruby -S rake install cd ..
Note: If the
rake install task fails under Windows, try again in two steps:
jruby -S rake package jruby -S gem install pkg\extlib-0.9.14.gem
Extlib is a collection of extensions to core Ruby classes and is currently used by both the DataMapper and Merb projects. However, it'll go away in future versions as we start to take advantage of the new, modular ActiveSupport in Rails 3.0.
Then proceed to install DataObjects:
git clone git://github.com/datamapper/do.git cd do cd data_objects jruby -S rake install cd ..
Next, decide on the driver for the database vendor you wish to use. If you're installing from source, there will be three components to install:
do_jdbc: DataObjects' JDBC support library. This is a Java library, packaged as a Jar, and then wrapped up as a RubyGem.
- the JDBC driver: the database vendor's driver using the JDBC API. Also a Java Jar, and in most cases, available wrapped up as RubyGems.
- the actual DataObjects' driver: written in Java and relies on the above two
libraries at runtime. Compiled against
do_jdbc (the DataObjects' JDBC support library):
cd do_jdbc jruby -S rake compile jruby -S rake install cd ..
To install the JDBC driver for the DataObjects driver, if you're using one of mysql, postgres, sqlite3 then we rely on ActiveRecord-JDBC to package the JDBC jar files as Gems for us. Installation should be a matter of:
jruby -S gem install jdbc-[DBNAME] jdbc-derby jdbc-h2 jdbc-hsqldb jdbc-mysql jdbc-postgres jdbc-sqlite3
If you're on Oracle, then you need to place the Oracle JDBC driver
in your Java load path. Read Raimond's blog article for more
If you're on SQL Server, the ActiveRecord-JDBC has not yet packaged the jTDS
JDBC driver as a RubyGem. However, we have this available in the DataObjects
repository (you may need hoe first
jruby -S gem install hoe):
cd jdbc_drivers/sqlserver jruby -S rake install cd ../..
Unless you've got your own project or have your mind set on a specific vendor's relational database, then follow this tutorial all the way through and install SQLite3 support (it means you won't have to do any configuration later!):
jruby -S gem install jdbc-sqlite3
Then you can proceed to install the DataObjects' driver:
cd do_[DBNAME] jruby -S rake compile jruby -S rake install cd ../..
Installing DataMapper's core and more gems should then be very straight-forward:
git clone git://github.com/datamapper/dm-core.git cd dm-core jruby -S rake install cd .. git clone git://github.com/datamapper/dm-more.git cd dm-more jruby -S rake install cd ..
The Merb maintainers just came out with a release (1.0.15) that should be compatible with DataMapper 0.10.x series. You should be able to install the gems as follows:
sudo jruby -S gem install merb-core merb-more
Create a Merb Project
Change to the project directory of your choice and use the
to create a "jump-start" Merb application. DataMapper is the default ORM for
this generator type.
cd ~/Projects jruby -S merb-gen app myapp cd myapp
Before you run the application, make sure the dependency versions in
config/dependencies.rb correspond with the "edge" versions you just installed.
Open config/dependencies.rb in your favourite text editor.
If the dependencies are out-of-date, then bump them appropriately:
merb_gems_version = "1.0.15" dm_gems_version = "~> 0.10" do_gems_version = "~> 0.10"
Note: The next major version of Merb, 1.1, will completely replace the dependency handling mechanism described here with Yehuda Katz's (wycats) Bundler. It's technically possible to use the Bundler with Merb 1.0.x series, but for concision, I won't elaborate on doing that here.
Before adding in any customisations of your own, check you're able to run the application.
Merb is built on Rack, and Rack needs a webserver. Webrick is a part of the Ruby standard library, so we could use that:
jruby -S merb -a webrick
-a flag specifies an adapter)
I encountered problems shutting down Webrick though, and had to kill it. Additionally, you'll probably want to use the server you'll end up deploying to, so let's try with Mongrel instead:
jruby -S gem install mongrel jruby -S merb -V
(this time with
-V to give us some verbose output)
I am personally a big fan of GlassFish for Java/JVM deployments. You can use something like Warbler to create a WAR file for deployment, but if you're coming from the Ruby world, the following is much simpler:
jruby -S gem install glassfish glassfish
Add a Model
Here I start to get lazy. Bereft of ideas, and starting to think about needing to cook, I decided to create a simple Recipe tracker. While introducing some of the cooler (and defining) DataMapper features will have to wait until a future article, this simple child-parent model should be immediately familiar to anyone who's done basic web development.
Create a file
app/models with the following contents:
class Ingredient include DataMapper::Resource property :id, Serial property :name, String, :length => 50, :nullable => false belongs_to :recipe, :nullable => true end
and a file
app/models with the following contents:
class Recipe include DataMapper::Resource property :id, Serial property :title, String, :length => 100, :nullable => false property :instructions, Text property :cooking_mins, Integer, :min => 5, :max => 120 has n, :ingredients end
If you chose SQLite3 as the relational database you wanted to use earlier, then
you don't need to change any database configuration. If you chose another
database, then open
config/database.yml and change appropriately. For
PostgreSQL, or Microsoft SQL Server configurations might look like the
# PostgreSQL development: &defaults adapter: postgres database: sample_development username: postgres password: host: localhost # Microsoft SQL Server development: &defaults adapter: sqlserver database: sample_development;instance=SQLEXPRESS; username: mswin password: doze host: sqlserver.localnet
Automigrate the database:
jruby -S rake db:automigrate
And run the application with one of the following commands:
jruby -S merb glassfish
Add a UI
Here I'm sorry to say we're going to cheat (yet again!). We're not actually
going to spend any time building a UI, but instead we'll rely on
project that automatically generates an admin front-end similar to Django,
the Python web application framework.
jruby -S gem install builder jruby -S gem install merb-admin -s http://gemcutter.org
In your app, add the following dependency to config/dependencies.rb:
dependency "merb-admin", "0.6.6"
Add the following route to config/router.rb (just after
slice(:merb_auth_slice_password, :name_prefix => nil, :path_prefix => "") slice(:merb_admin, :path_prefix => "admin")
Then, run the following rake task:
jruby -S rake slices:merb-admin:install
Fire up your application, with one of the following commands:
jruby -S merb glassfish
Visit http://localhost:4000/admin, or if you're running with glassfish, http://localhost:3000/admin.
You should have now have an application with a (very) simple interface for adding recipes and ingredients.
You can find the source code for this application on GitHub.
That's it for now! Please leave a comment and let me know what (if anything) was useful, so that I can focus my efforts for future articles.
UPDATE 1 Dec 2009: Grammar, spelling fixes. Added note on Jeweler.