Monday, June 01, 2009

Packaging a Rails 1.1 app for JRuby

I've recently needed to "convert" a Rails 1.1 app to run under JBoss using JRuby to improve the deployment story and long-term maintenance for a new virtual server. The configuration/conversion wasn't without significant hiccups. I'll try to cover in some detail here what I did to get things working.

First, I tried upgrading to Rails 2.x. Don't try this. If you're not a professional Rails developer, you'll likely tear your hair out and ask yourself why you ever decided to use Rails in the first place. In my case, upgrading would have required a near total re-write of the (very simple) app.

For the impatient, here's the basic gist of what I did.


  1. update config/boot.rb, require_gem -> gem

  2. freeze to edge, RELEASE=1.1.4

  3. reset config/boot.rb(?) -> rake rails:update

  4. pluginize warbler

  5. update environment.rb

  6. create jboss-web.xml

  7. create -ds.xml file

  8. create warble.rb

  9. update warble.rb

  10. update database.yml -- copy production: block

  11. update new/thankyou.rhtml (change absolute links)

  12. add close_connections.rb

  13. edit new_rails_defaults.rb



I used JRuby 1.2.0 on a Rails 1.1.4 app, deploying to a JBoss 4.2.0.GA application server against a MySQL 4.1 database.

This isn't meant to be a list you can work off, merely a list showing what's involved, so if you count yourself amongst the faint of heart, stop here :).

update config/boot.rb, require_gem -> gem


If you don't actually have the original RubyGems that you had when you started your Rails 1.x project, some things have changed. Most particularly, require_gem is no longer deprecated, its GONE! So, edit
config/boot.rb
by changing the two instances of require_gem to simply gem. That wasn't too hard :)

freeze to edge, RELEASE=1.1.4


Now you're ready to freeze. You really want to freeze because it will simplify things down the road for your warbler tasks and runtime within JRuby. Until I froze, I kept having oodles of issues that basically track down to various commands trying to do things in my Rails project whilst executing code from the latest Rails on my system (2.3.2, I think). You should be able to freeze to just about any RELEASE or TAG you want. Either of the following should work:

$ rake rails:freeze:edge TAG=rel_1-1-4
$ rake rails:freeze:edge RELEASE=1.1.4


reset config/boot.rb(?) -> rake rails:update


Guess what? Now we need to undo step #2. But, this is pretty easy. You can either manually revert the changes you made to boot.rb, or just run:

$ rake rails:update


Which, contrary to its name, shouldn't do anything terribly crazy other than reset your boot.rb back to what it was previously (and it does this now based on your *frozen* Rails, not whatever the latest is in your system).

pluginize warbler


Assuming you've installed Warbler (if you haven't, gem install warbler) - let's take the road less travelled and pluginize. This keeps everything in a nice local package. It also means you can use the normal rake commands instead of

jruby -S warble <cmd>


Alright, to pluginize, straight from warbler's docs:

$ jruby -S warble pluginize


update environment.rb


Not sure where I found this, but it appears to be essential. Running in the JRuby environment appears to take a a few gems that aren't included elsewhere, so update your
config/environment.rb
to include the following:


if RUBY_PLATFORM =~ /java/
require 'rubygems'
RAILS_CONNECTION_ADAPTERS = %w(jdbcmysql)
require 'active_record'
gem 'activerecord-jdbcmysql-adapter'
require 'active_record/connection_adapters/jdbcmysql_adapter'
end


Insert this immediately preceding the line that looks like this:

Rails::Initializer.run do |config|


create jboss-web.xml


I wanted to create a configuration that takes advantage of JBoss' connection pools for connections to MySQL, unfortunately (dirty secret), I haven't gotten it to work yet. Soooo, you can consider this step optional. Once I figure out what piece is missing to get JNDI DataSource access working, however, this piece will certainly be needed, so, take it or leave it :)

The jboss-web.xml maps an application-local resource-ref to a global JNDI name. Typically used to map a 'generic' JNDI ref such as jdbc/rails to a specific ref, such as jdbc/my_cool_apps/app1. Of course, you could just use jdbc/my_cool_apps/app1, but the thinking is that a level of indirection helps when you need to change things - you just change a config at the container level and don't need to muck about with the app (repackaging/redeploying/etc.). Again, YMMV, take it or leave it.

Here it is:


<?xml version="1.0" encoding="UTF-8"?>
<jboss-web>
<resource-ref>
<res-ref-name>jdbc/rails</res-ref-name>
<jndi-name>jdbc/my_cool_apps/app1</jndi-name>
</resource-ref>
</jboss-web>


create -ds.xml file


Now that you've mapped the local JNDI name to the global JNDI name, you should probably setup the configuration in JBoss that creates the global JNDI name. Here it is (substitute in your own parameters):


<?xml version="1.0" encoding="ISO-8859-1"?>
<datasources>
<local-tx-datasource>

<jndi-name>jdbc/my_cool_apps/app1</jndi-name>

<connection-url>jdbc:mysql://mysql.example.com:3306/mydb</connection-url>
<driver-class>com.mysql.jdbc.Driver</driver-class>

<user-name>my_username</user-name>
<password>secret</password>

<!-- Typemapping for JBoss 4.0 -->
<metadata>
<type-mapping>mySQL</type-mapping>
</metadata>

</local-tx-datasource>
</datasources>


This by far isn't the most sophisticated DataSource you can configure, but there are better references elsewhere for the options available.

This gets dropped in the JBoss application server's "deploy" directory to setup the DataSource in global JNDI.

create warble.rb


Alright, back to the app. Let's create the warble config file, mostly run on defaults, but we need a couple customizations.

$ jruby -S warble config

-OR-
$ script/generate warble


I had some issues with the latter, can't remember if that was before I figured out I needed to freeze, but the first way worked for me, YMMV.

update warble.rb


Documentation for warbler contains oodles of information on configuring, I found no fault with that information. Here's what I did:

Added

config.includes = FileList["jboss-web.xml"]
config.gems += ["activerecord-jdbcmysql-adapter"]


Set
config.gems["rails"] = "1.1.4"

(use whatever version suits you)

Uncommented
config.webxml.jndi = 'jdbc/rails'


That's it!

update database.yml -- copy production: block


So, here's where, if the world were a happy place, I'd tell you how to configure database.yml to use JNDI. Unfortunately, following the available documentation, I haven't gotten this to work. So, instead, I'll show you how to switch to use the 'jdbcmysql' adapter, instead of the 'mysql' adapter.

Change

adapter: mysql

To
adapter: jdbcmysql

Painful, I know. You'll need to use a host: parameter, too, JDBC doesn't connect to /tmp/mysql.sock.

update new/thankyou.rhtml (change absolute links)


Not sure this applies to everyone, by my .rhtml files had absolute references in them to static resources. That needs to change to use relative paths that resolve to within your application. Just removing the leading '/' did the trick for me.

add close_connections.rb


This may be an optional step, I think its only needed if you do use JNDI (not in use here, yet). In any case, you'll want to add an initializers/close_connections.rb to config in your app. Contents:


if defined?($servlet_context)
require 'action_controller/dispatcher'
ActionController::Dispatcher.after_dispatch do
ActiveRecord::Base.clear_active_connections!
end
end


edit new_rails_defaults.rb


Finally (are you still reading?!), the spec for warbler uses a Rails 2.x (I think) JSON config, this needs to be commented out. Find your new_rails_defaults.rb under vendor/plugins/warbler-0.9.13 (version may vary), and comment out the last line.

#ActiveSupport.escape_html_entities_in_json = false


That's it!! Seriously.

Use a line like this to package/repackage/deploy your .WAR and enjoy.

rake war:clean; rake war; \
if [ -e <rails_app>.war ]; then
unzip -q -o -d $JBOSS_HOME/server/default/deploy/<rails_app>.new <rails_app>.war;
mv $JBOSS_HOME/server/default/deploy/<rails_app>.war $JBOSS_HOME/server/default/deploy/<rails_app>.old;
mv $JBOSS_HOME/server/default/deploy/<rails_app>.new $JBOSS_HOME/server/default/deploy/<rails_app>.war;
rm -rf $JBOSS_HOME/server/default/deploy/<rails_app>.old ;
fi


Where <rails_app> is your app name; $JBOSS_HOME is set to your JBoss install dir. BEWARE - I chased my tail AROUND AND AROUND because I didn't realize that (a) rake war doesn't clean tmp/war before setting up & repackaging the WAR, so if you're trying to fix things, your old stuff may still be around; similarly, unless you're deploying the packaged WAR file, JBoss doesn't do you any favors and you should remove the exploded WAR before placing your fresh WAR dir in the deploy dir.

41 comments:

眼光 said...

so cool.................................................

感冒 said...

一起加油吧..................................................

more said...

經驗是良師,可惜學費貴..............................

餐廳 said...

請繼續發表好文!加油加油加油!........................................

easy said...

正妹自拍美女走光辣妹走光正妹走光脫衣秀脫衣走光色情自慰自拍成人全裸打炮打手槍打飛機巨乳巨奶女優大奶性交性愛淫蕩淫慾淫亂淫婦淫妹淫叫淫水淫女情慾情色做愛限制級波霸口交

婉亞 said...

how do u do?

吳怡迪 said...

It's great!!..................................................

SydneyJ21074 said...

人並不是生來要吃敗仗的。人可被毀滅,但不可被擊倒。..................................................

淑慧 said...

本土性愛自拍圖台灣本土性愛性愛a成人性愛站明星性愛成人dvd下載成人dvd免費看成人go成人go2成人hbo成人kk俱樂部成人人圖成人大全成人片a片成人片gogo成人片gogosex成人卡通色情片白虎圖庫尼可成人網弘爺論壇打非打非機專用網打炮論壇打飛機專區打砲遊戲打砲網站本土付費av本土成人直播本土自拍小弟弟本土性自拍影片85cc聊天室aio交友愛情館成人視訊

宛蓉 said...

how do u do?xvideo打飛機專用網洪爺免費洪爺色情片洪爺貼圖區洪爺成人線上洪爺影城洪爺色論壇洪爺貼圖洪爺成年人網洪爺免費色情洪爺色情貼援交妹辣妹野球拳情色文學情趣聊天室性感辣妹裸體遊戲做愛偷拍一夜情視訊洪爺色情貼洪爺免費色情洪爺成年人網洪爺貼圖洪爺色論壇洪爺影城洪爺成人線上洪爺貼圖區洪爺色情片洪爺免費洪爺色情貼洪爺免費色情洪爺成年人網洪爺貼圖洪爺色論壇洪爺影城洪爺成人線上洪爺貼圖區洪爺色情片洪爺免費洪爺免費洪爺色情片洪爺貼圖區洪爺影城洪爺色論壇洪爺貼圖洪爺成年人網洪爺免費色情洪爺色情貼洪爺成人線上

育德 said...

Necessity is the mother of invention................................................................

冠廷 said...

成人卡通貼圖區亞洲成人文成人dvd影城線上免費看成人卡通成人色情電影院台灣成網台灣自拍論壇台灣自慰影片台灣色小說台灣色文學台灣色文學網台灣情kiss網台灣情網色網台灣論壇區外國色片外國色情網站外國色情影片外國免費a片外國免費色情外國免費影片外國美女做愛外國美女圖外國美女圖片外國美女寫真孕婦做愛小說孕婦做愛自拍台灣論壇小說區台灣論台台灣線上a片王台灣情論壇凹凸色色卡通圖片免費即時通視訊美女色情

佳俐 said...

人逢順境不逞強,身處逆境不示弱。........................................

清民 said...

有空我一定會常來逛你的部落格!!!! ..............................

怡茂恒臻 said...

成熟,就是有能力適應生活中的模糊。..................................................

思姿穎穎 said...

As a man sows, so he shall reap...................................................

kittycha said...

Constant dripping wears away the stone. 滴水穿石!加油!..................................................

淑慧 said...

來給你加油打氣!!!保重!!! .................................................................

喜妤 said...

初次造訪,安安^^

江婷 said...

所有的資產,在不被諒解時,都成了負債.................................................................

WallaceD依來 said...

一個人的價值,應該看他貢獻了什麼,而不是他取得了什麼.................................................................                           

asdas said...

成熟,就是有能力適應生活中的模糊。.................................................................

育財育財 said...

人不能像動物一樣活著,而應該追求知識和美德............................................................

芸茂芸茂 said...

安一估~你也安一估哦~............................................................

新順 said...

faith will move mountains. ..................................................

雲亨雲亨雲亨 said...

Readiness is all.............................................................

香昱信張君林 said...

開懷幸福的生活,是每個人的夢想~~希望大家都能夠實現!............................................................

吳玉婷 said...

Of two evils choose the least.............................................................

陳璇竹陳璇竹 said...

很用心的部落格 祝你人氣百分百 期待您的新文章..................................................................

原秋原秋 said...

獨居時,要反省自己的過錯;在社會大眾之間,則要忘卻別人的過失。..................................................

芳瑜芳瑜 said...

有用的才華若不用,便如同日晷儀放在陰暗之中............................................................

佳瑩佳瑩 said...

來看看你逛逛blog囉,加油!............................................................

許惠吟許惠吟 said...

Learn wisdom by the follies of others.............................................................

施以王雅玲音 said...

時間就是塑造生命的材料。

家唐銘 said...

時間就是塑造生命的材料。

建邱勳 said...

人有兩眼一舌,是為了觀察倍於說話的緣故。............................................................

建鄭勳建鄭勳 said...

知識可以傳授,智慧卻不行。每個人必須成為他自己。............................................................

麗王王珠 said...

愛情是盲目的,但婚姻恢復了它的視力。......................................................................

1615 said...

謝謝大大的分享 我會學會反省與寬容 感恩 ∩△∩............................................................

國林林林林維 said...

喜歡你的部落格,讓人流連忘返..................................................................

怡靜怡靜怡靜怡雯 said...

良言一句三冬暖,惡語傷人六月寒。............................................................