For political reasons, I needed to ship a single jar file. I didn’t want to have the overhead of a war & an appserver, so I set out to embed my rails app within a single jar file. I needed to make some changes in order to get it to work.
This assumes Rails 2.3.5 and JRuby 1.4.0.
First, you need to create your rails app. Freeze rails and any gems required.
Next download jruby-complete. Once you’ve done so, unzip it. I’m assuming you’ve unzipped it to complete.
Note: When you repackage the jar file, DO NOT use jar. Use zip. This is very important. If you don’t, you’ll trash your jruby instance.
Copy your rails instance to
complete/META-INF/jruby.home. I assume it will be
complete/META-INF/jruby.home/bin/server with the following content:
#!/usr/bin/env ruby RAILS_ROOT = File.join(File.dirname(File.dirname(__FILE__)),'rails') require File.join(RAILS_ROOT,'config/boot') require 'commands/server'
RAILS_ROOT needs to be set in order to have the proper paths within the jar file.
complete/META-INF/jruby.home/rails/vendor/rails/railties/lib/initializer.rb In the
set_root_path method, edit it so it looks like this:
def set_root_path! raise 'RAILS_ROOT is not set' unless defined?(::RAILS_ROOT) raise 'RAILS_ROOT is not a directory' unless File.directory?(::RAILS_ROOT) # I changed this... mkw21 20100301 @root_path = RAILS_ROOT # Pathname is incompatible with Windows, but Windows doesn't have # real symlinks so File.expand_path is safe. # if RUBY_PLATFORM =~ /(:?mswin|mingw)/ # File.expand_path(::RAILS_ROOT)# # Otherwise use Pathname#realpath which respects symlinks. # else # Pathname.new(::RAILS_ROOT).realpath.to_s # end Object.const_set(:RELATIVE_RAILS_ROOT, ::RAILS_ROOT.dup) unless defined?(::RELATIVE_RAILS_ROOT) ::RAILS_ROOT.replace @root_path end
This is related to paths within the jar file.
Additionally, you need to change the
initialize_logger method. (this might not be needed, see below). Change
logger = ActiveSupport::BufferedLogger.new(configuration.log_path)
logger = ActiveSupport::BufferedLogger.new("/tmp/transfer.log")
The idea is to change it to something definitely outside the jar. The reason I did this, and didn’t change the config in
environment.rb was that the changes in environment.rb were not getting picked up. I’ve since come to the belief that this is due to an issue with the Rack
LogTailer detailed at https://rails.lighthouseapp.com/projects/8994/tickets/2350-logtailer-ignores-configlog_path. So
complete/META-INF/jruby.home/rails/vendor/rails/railties/lib/rails/rack/log_tailer.rb needs to be edited. Edit the
EnvironmentLog assignment to match the file we’d specified. (You may be able to substitute
RAILS_DEFAULT_LOGGER but I have not tested that)
EnvironmentLog = "/tmp/transfer.log"
That’s pretty much it. Zip up your exploded jar from the
zip -r ../complete.zip *. Then you can run it via
java -jar complete.jar -S server.