• Create a simple CRUD application with Rails (one that uses Ruby MRI)
  • Convert our Ruby on Rails application to a JRuby on Rails application
  • Generate a WAR file for the application
  • Install Apache Tomcat 7
  • Deploy the WAR file to the Tomcat server

At the end of the tutorial, you'll have a working JRuby on Rails application deployed.

Introduction

Ruby on Rails (RoR) is a very popular framework that enables developers to quickly create web applications that adhere to modern design patterns. Using Rails, with just a few commands, you can build a production-ready vanilla CRUD (Create, Read, Update, Delete) application without having to write any code at all. Apache Phusion Passenger, Unicorn, and Puma are some of the popular servers which are used to run Rails applications.

The performance of Ruby MRI has improved considerably over the years. However, it is still slow compared to languages like Java or C. If you are interested in faster write times, which is necessary for critical, concurrent, distributed, and enterprise-grade applications, you should use JRuby instead, a Java implementation of Ruby.

Some Advantages of JRuby over Ruby MRI

Concurrency — Ruby MRI uses GIL (Global Interpreter Lock), and consequently has limited concurrency. JRuby, on the other hand, is able to use JVM's threads, allowing you to achieve much higher levels of concurrency. This is usually the most important reason why JRuby is chosen over other Rubies.

Thread safety — Most of Ruby's core classes are not thread-safe. Using such classes in multi-threaded applications is error-prone. JRuby is capable of using Java's classes instead, which are designed for parallel processing.

More libraries — When you use JRuby, you have at your disposal not only a repertoire of Ruby gems but also all Java and Scala libraries. This lets you focus more on your application's core functionality.

Ease of deployment — A JRuby on Rails application can be packaged into a single WAR file, which can be trivially deployed to any Java EE server. A lot of them even have browser-based interfaces to manage applications.

What This Tutorial Covers

In this tutorial you will learn to:

  • Create a simple CRUD application with Rails (one that uses Ruby MRI)
  • Convert our Ruby on Rails application to a JRuby on Rails application
  • Generate a WAR file for the application
  • Install Apache Tomcat 7
  • Deploy the WAR file to the Tomcat server

At the end of the tutorial, you'll have a working JRuby on Rails application deployed.

Prerequisites

  • Deploy a 32-bit Ubuntu 14.04 Droplet. Tomcat and JRuby will run on a 64-bit server, but will likely be slower.
  • Create a sudo user.
  • If your Droplet has less than 2 GB of RAM, you should add at least 1 GB of swap space. Refer to the following tutorial for more information: How To Add Swap on Ubuntu 14.04.
				
					
gpg --keyserver hkp://keys.gnupg.net --recv-keys D39DC0E3

				
			

Follow that tutorial through the <^>rvm requirements<^> command.

Step 1 — Create a Simple CRUD RoR Application

application illustration for: Step 1 — Create a Simple CRUD RoR Application

Initialize RVM. This initialization is necessary for every new terminal you open.

				
					
. ~/.rvm/scripts/rvm

				
			

> Note: If you already have a Rails application that uses Ruby 1.9.3, you can now skip to Step 2.

Create a directory to house all your Rails applications, and enter that directory.

				
					
mkdir ~/my_applications

cd ~/my_applications

				
			

We use Ruby 1.9.3 for this tutorial, because that is the latest version of Ruby that JRuby supports.

				
					
rvm install 1.9.3

rvm use 1.9.3

				
			

Install Rails.

				
					
gem install rails -N

				
			

Create a new Rails application, called simple.

				
					
rails new simple

				
			

Enter the application's directory.

				
					
cd ~/my_applications/simple

				
			

Use nano to edit the <^>Gemfile<^> and uncomment the line for the gem therubyracer. This gem has to be added because our Rails application needs a JavaScript runtime.

				
					
nano ~/my_applications/simple/Gemfile

				
			

Ignoring the comments, your updated file should look like this:

				
					
source 'https://rubygems.org'



gem 'rails', '4.1.7'

gem 'sqlite3'

gem 'sass-rails', '~&gt; 4.0.3'

gem 'uglifier', '&gt;= 1.3.0'

gem 'coffee-rails', '~&gt; 4.0.0'

&lt;^&gt;gem 'therubyracer'&lt;^&gt;

gem 'jquery-rails'

gem 'turbolinks'

gem 'jbuilder', '~&gt; 2.0'

gem 'sdoc', '~&gt; 0.4.0',          group: :doc

gem 'spring',        group: :development

				
			

You'll want to remove the , platforms: :ruby portion of the commented therubyracer line, because eventually we'll be using JRuby rather than Ruby.

Install all the gems listed in the <^>Gemfile<^>.

				
					
bundle install

				
			

Add a few pages to the application using Rails' scaffolding feature.

				
					
rails g scaffold Employee name:string age:integer address:text

				
			

The rails g scaffold command generates a few migrations. Apply them:

				
					
rake db:migrate

				
			

Change the root of the application to show the list of all employees. Use nano to edit ~/my_applications/simple/config/routes.rb and change its contents to what's shown below, minus the comments:

				
					
Rails.application.routes.draw do

  resources :employees

  &lt;^&gt;root 'employees#index'&lt;^&gt;

end

				
			

Your Rails application that uses Ruby MRI is now ready. Run it on the development server by typing in:

				
					
rails s

				
			

This will take a minute or two to start up.

You can visit the application in your browser by visiting http://<server-IP>:3000. Create a couple of records to make sure everything is working as expected.

Return to your console, and stop the server by pressing Ctrl+C.

Step 2 — Install Java 8

In order to install and use JRuby, a JDK is required. Oracle JDK 8 can be installed using <^>apt-get<^> after adding the webupd8team/java PPA.

Add the repository by typing in the following:

				
					
sudo add-apt-repository ppa:webupd8team/java

				
			

Press Enter to accept the new repository.

Update <^>apt-get<^>'s package index files.

				
					
sudo apt-get update

				
			

Install Oracle JDK 8.

				
					
sudo apt-get install oracle-java8-installer

				
			

Note: You will be prompted to accept a license agreement before the actual installation begins.

Select <Ok> and press Enter, then select <Yes> and press Enter.

After the installation is complete, run the command:

				
					
java -version

				
			

You should be able to see the following output, which means Java was installed correctly:

				
					
java version "1.8.0_25"

Java(TM) SE Runtime Environment (build 1.8.0_25-b17)

Java HotSpot(TM) Client VM (build 25.25-b02, mixed mode)

				
			

Step 3 — Install JRuby and JRuby on Rails

Use RVM to install and use JRuby.

				
					
rvm install jruby

rvm use jruby

				
			

The latest version of JRuby (1.7.16.1 as of November 2014) is now ready to be used. Check the version:

				
					
jruby -v

				
			

This shows you your server is using Oracle JDK 8. You should see output similar to this:

				
					
jruby 1.7.16.1 (1.9.3p392) 2014-10-28 4e93f31 on Java HotSpot(TM) Client VM 1.8.0_25-b17 +jit [linux-i386]

				
			

Install JRuby on Rails.

				
					
gem install rails -N

				
			

JRuby on Rails is now installed.

Step 4 — Configure the Application to Use JRuby

While a lot of Ruby MRI gems are supported by JRuby seamlessly, some gems that have native code aren't. Most gems that are interfaces to databases fall into this category. Our application currently uses the sqlite3 gem, which is not supported by JRuby. activerecord-jdbcsqlite3-adapter should be used instead.

Similarly, JRuby uses therubyrhino instead of the therubyracer gem as a JavaScript engine.

Use nano to edit ~/my_applications/simple/Gemfile to make this change.

				
					
nano ~/my_applications/simple/Gemfile

				
			

Your file should look like this after updating the two lines, minus the comments:

				
					
source 'https://rubygems.org'



gem 'rails', '4.1.7'

gem &lt;^&gt;'activerecord-jdbcsqlite3-adapter'&lt;^&gt;

gem 'sass-rails', '~&gt; 4.0.3'

gem 'uglifier', '&gt;= 1.3.0'

gem 'coffee-rails', '~&gt; 4.0.0'

gem &lt;^&gt;'therubyrhino'&lt;^&gt;

gem 'jquery-rails'

gem 'turbolinks'

gem 'jbuilder', '~&gt; 2.0'

gem 'sdoc', '~&gt; 0.4.0',          group: :doc

gem 'spring',        group: :development

				
			

If you didn't before, now you need to remove the platform setting from the <^>therubyrhino<^> line.

Some of our gems require native extensions. Type in the following to allow JRuby to support C extensions.

				
					
echo "cext.enabled=true" &gt;&gt; ~/.jrubyrc

				
			

You can now install the newly-added gems.

				
					
bundle install

				
			

If you are not using SQLite3 as a database, you might need one of these gems:

  • For Derby: activerecord-jdbcderby-adapter
  • For MySQL: activerecord-jdbcmysql-adapter
  • For Postgres: activerecord-jdbcpostgresql-adapter

Step 5 — Update Java's Policy Files

Using a browser, download the JCE Unlimited Strength Jurisdiction policy files. You will have to accept Oracle's License Agreement first.

(You can't <^>wget<^> the files because you have to accept the agreement.)

On your local computer, upload the file to your server using scp:

				
					
scp &lt;^&gt;Downloads/&lt;^&gt;jce_policy-8.zip &lt;^&gt;user&lt;^&gt;@&lt;^&gt;server-ip&lt;^&gt;:~

				
			

On your server, install the unzip utility:

				
					
sudo apt-get install unzip

				
			

Unzip the file in a directory in <^>/tmp<^>.

				
					
cd /tmp

unzip ~/jce_policy-8.zip

				
			

Copy the policy files to the JRE's <^>lib/security<^> directory.

				
					
cd /tmp/UnlimitedJCEPolicyJDK8

sudo cp *.jar /usr/lib/jvm/java-8-oracle/jre/lib/security/

				
			

Go back to your application's directory.

				
					
cd ~/my_applications/simple

				
			

Execute the following command to speed up the JVM startup. This is necessary because virtual server environments tend to generate very little randomness on their own.

				
					
export JAVA_OPTS="-Djava.security.egd=file:/dev/./urandom" 

				
			

At this point, our Rails application is fully configured to use JRuby. Start the development server:

				
					
rails s

				
			

This server might take several seconds to start. Wait till you see the following output before proceeding:

				
					
=&gt; Booting WEBrick

=&gt; Rails 4.1.7 application starting in development on http://0.0.0.0:3000

=&gt; Run `rails server -h` for more startup options

=&gt; Notice: server is listening on all interfaces (0.0.0.0). Consider using 127.0.0.1 (--binding option)

=&gt; Ctrl-C to shutdown server

[2014-11-06 04:38:15] INFO  WEBrick 1.3.1

[2014-11-06 04:38:15] INFO  ruby 1.9.3 (2014-09-25) [java]

[2014-11-06 04:38:15] INFO  WEBrick::HTTPServer#start: pid=2620 port=3000

				
			

Use a browser to visit http://<server-ip>:3000 and test your application. Except for the fact that it is currently running on the JVM instead of using Ruby MRI, you should find nothing different about the application.

Return to the terminal and press Ctrl+C to stop the server.

Step 6 — Package the Application as a Deployable WAR File

To run the JRuby on Rails application on a servlet container like Tomcat, it should first be packaged into a WAR (Web application ARchive) file. This can be done using the warbler gem.

Install warbler.

				
					
gem install warbler

				
			

The SQLite database that our application uses is currently present in the application's directory. When the WAR file is generated, the database in its current state will be placed inside the WAR file. We do not want this, because any changes that are made to the database after deployment will be overwritten if the application is redeployed.

Therefore, the SQLite database files should be moved to a location outside the application's directory.

Create a new directory for the databases:

				
					
mkdir -p ~/databases/simple

				
			

In this tutorial, we are only concerned about the development database. Therefore, move the development database file to the newly-created directory:

				
					
mv ~/my_applications/simple/db/development.sqlite3 ~/databases/simple

				
			

Edit the <^>database.yml<^> file using nano.

				
					
nano ~/my_applications/simple/config/database.yml

				
			

Update the path of the development database. You can also remove the details for other environments, because you won't be needing them for this tutorial. After the changes, your file should look like this:

				
					
default: &amp;default

  adapter: sqlite3

  pool: 5

  timeout: 5000



development:

  &lt;&lt;: *default

  database: &lt;^&gt;~/databases/simple/development.sqlite3&lt;^&gt;

				
			

Warbler also needs to know the Rails environment of the WAR. In this tutorial, we stick to the <^>development<^> environment. This is specified using a config/warble.rb file.

Use nano to create a new file named <^>warble.rb<^>

				
					
nano ~/my_applications/simple/config/warble.rb

				
			

Add the following to the file:

				
					
Warbler::Config.new do |config|

  config.webxml.rails.env = &lt;^&gt;'development'&lt;^&gt;

end

				
			

Our application is now ready to be packaged into a WAR file. Run the following command to generate the file:

				
					
warble executable war

				
			

This will take a few moments.

Successful output should look like:

				
					
Downloading winstone-0.9.10-jenkins-43.jar

rm -f simple.war

Creating simple.war

				
			

At this point, there will be a file named <^>simple.war<^> in your application's directory. Adding the argument <^>executable<^> to the command generates a WAR file that has a tiny embedded server (called Winstone) in it. This file can be used indepedently (without any external server) as follows:

				
					
java -jar simple.war

				
			

This is a good way to check for any problems with your WAR file. You can now use a browser to visit http://<server-ip>:8080. After a few minutes, you should be able see your application working correctly. All the entries you made in the database application earlier should be visible here.

You should wait until you see output similar to the following, to let you know that the server has started:

				
					
Nov 13, 2014 12:24:37 PM winstone.Logger logInternal

INFO: Started GET "/assets/application.js?body=1" for 108.29.37.206 at 2014-11-13 12:24:37 -0500

				
			

Return to the terminal, and press Ctrl+C to stop the embedded server.

Now that you have confirmed that the application is working as a WAR, generate a new WAR for Tomcat using the following command:

				
					
warble war

				
			

It will replace the old executable WAR with a new WAR file that doesn't have any embedded server in it.

Step 7 — Install and Start Tomcat

Download the latest version of Tomcat.

				
					
cd ~

wget http://mirror.cc.columbia.edu/pub/software/apache/tomcat/tomcat-7/v7.0.56/bin/apache-tomcat-7.0.56.tar.gz

				
			

Create a new directory for Tomcat and enter that directory.

				
					
mkdir ~/Tomcat

cd ~/Tomcat

				
			

Extract the archive:

				
					
tar -xvzf ~/apache-tomcat-7.0.56.tar.gz

				
			

Set the maximum heap size available to Tomcat to 512m to avoid java.lang.OutOfMemoryError. This export has to be done every time you start the Tomcat server.

				
					
export CATALINA_OPTS="-Xmx512m"

				
			

As before, set the randomness generation:

				
					
export JAVA_OPTS="-Djava.security.egd=file:/dev/./urandom"

				
			

Start Tomcat:

				
					
~/Tomcat/apache-tomcat-7.0.56/bin/catalina.sh start

				
			

This server too takes several seconds to start. To monitor its logs, type in:

				
					
tail -f ~/Tomcat/apache-tomcat-7.0.56/logs/catalina.out

				
			

When the server is ready, you will see log messages like these:

				
					
Nov 10, 2014 4:12:32 AM org.apache.catalina.startup.HostConfig deployDirectory

INFO: Deployment of web application directory ~/Tomcat/apache-tomcat-7.0.56/webapps/manager has finished in 210 ms

Nov 10, 2014 4:12:32 AM org.apache.coyote.AbstractProtocol start

INFO: Starting ProtocolHandler ["http-bio-8080"]

Nov 10, 2014 4:12:32 AM org.apache.coyote.AbstractProtocol start

INFO: Starting ProtocolHandler ["ajp-bio-8009"]

Nov 10, 2014 4:12:32 AM org.apache.catalina.startup.Catalina start

INFO: Server startup in 3390 ms

				
			

Press Ctrl+C to end the <^>tail<^> command.

Tomcat is now installed and running. You can use a browser to visit http://<server-ip>:8080. You should be able to see Tomcat's welcome page.

Step 8 — Deploy the Application to Tomcat

To deploy a WAR to Tomcat, all you have to do is copy it to Tomcat's <^>webapps<^> folder.

				
					
cp ~/my_applications/simple/simple.war ~/Tomcat/apache-tomcat-7.0.56/webapps

				
			

It might take a minute or so for your application to be automatically deployed. While you are waiting, you can monitor the contents of Tomcat's log file using:

				
					
tail -f ~/Tomcat/apache-tomcat-7.0.56/logs/catalina.out

				
			

When your application is ready to be used, you will see log messages like these:

				
					
INFO: Deploying web application archive ~/Tomcat/apache-tomcat-7.0.56/webapps/simple.war

Oct 30, 2014 4:42:35 AM org.apache.catalina.startup.HostConfig deployWAR

INFO: Deployment of web application archive ~/Tomcat/apache-tomcat-7.0.56/webapps/simple.war has finished in 47,131 ms

				
			

Press Ctrl+C to end the tail command.

You can now use a browser to visit http://<server-ip>:8080/simple/ and see your JRuby on Rails application running on Tomcat.

Restarting Your Session

If you disconnect from your SSH session at any time, you should run the following three commands:

				
					
cd ~/my_applications/simple

. ~/.rvm/scripts/rvm

rvm use jruby

				
			

And if you need to restart Tomcat, run the previous three commands, and make sure you set the two environment variables before starting the server:

				
					
export CATALINA_OPTS="-Xmx512m"

export JAVA_OPTS="-Djava.security.egd=file:/dev/./urandom"

~/Tomcat/apache-tomcat-7.0.56/bin/catalina.sh start

				
			

Conclusion

Thus, a Ruby on Rails application can be converted into a JRuby on Rails application with just a few configuration changes. JRuby on Rails applications can run on almost all servlet containers. In this tutorial, you have already seen how to run one on Apache Tomcat and Winstone.