Nick Sieger: Tag jrubytag:blog.nicksieger.com,2005:TypoTypo2010-11-22T18:03:42+00:00Nick Siegerurn:uuid:8f70150f-ec57-4646-afaa-c3e07b6df7c32010-10-14T15:25:51+00:002010-11-22T18:03:42+00:00activerecord-jdbc-adapter 1.0.0<p>Just a quick note that <code>activerecord-jdbc-adapter</code> has finally hit 1.0.0. Install it today:</p>
<pre><code>gem install activerecord-jdbc-adapter
</code></pre>
<p>Included are adapters for <a href="http://www.mysql.com/" title="MySQL :: The world's most popular open source database">MySQL</a>, <a href="http://www.postgresql.org/" title="PostgreSQL: The world's most advanced open source database">PostgreSQL</a>, <a href="http://www.sqlite.org/" title="SQLite Home Page">SQLite3</a>, <a href="http://db.apache.org/derby/" title="Apache Derby">Derby</a>, <a href="http://hsqldb.org/" title="HSQLDB">HSQLDB</a>, <a href="http://www.h2database.com/" title="H2 Database Engine">H2</a>, and <a href="http://www.microsoft.com/sqlserver/2008/en/us/" title="SQL Server 2008 Overview, data platform, store data | Microsoft">Microsoft SQL Server</a>.</p>
<pre><code>gem install activerecord-jdbcmysql-adapter
gem install activerecord-jdbcpostgresql-adapter
gem install activerecord-jdbcsqlite3-adapter
gem install activerecord-jdbcderby-adapter
gem install activerecord-jdbchsqldb-adapter
gem install activerecord-jdbch2-adapter
gem install activerecord-jdbcmssql-adapter
</code></pre>
<p>You can also use <code>activerecord-jdbc-adapter</code> with Oracle, DB2, Sybase, and Informix. Just ensure that the database JDBC driver jar files are mentioned in <code>$CLASSPATH</code> or <code>require</code> them directly in your script or application. Then, configure <code>database.yml</code> with <code>adapter:</code> set to one of <code>oracle</code>, <code>db2</code>, <code>sybase</code>, or <code>informix</code>.</p>
<p>This release promises superb compatibility with Rails 3. We now have the ActiveRecord test suite <a href="http://ci.jruby.org/view/Rails">running in CI</a> and the 1.0.0 release is 100% green when run on MySQL. (SQLite3 is right behind with just 13 failures, and we hope to fix those soon.)</p>
<p>As <a href="/articles/2010/02/24/jruby-and-rails-3-sitting-in-a-tree">mentioned before</a>, to get started with Rails 3, JRuby and <code>activerecord-jdbc-adapter</code>, simply run:</p>
<pre><code>$ rails new app --database mysql --template http://jruby.org
...
apply http://jruby.org
apply http://jruby.org/templates/default.rb
gsub Gemfile
gsub config/database.yml
$ cd app && bundle install
...
Using activerecord-jdbc-adapter (1.0.0)
...
Using jdbc-mysql (5.0.4)
...
Using rails (3.0.0)
Your bundle is complete! Use `bundle show [gemname]` ...
</code></pre>
<p>One new feature in 1.0.0 is the ability to define an extension adapter for your proprietary JDBC database without needing to hack the <code>activerecord-jdbc-adapter</code> source code. To get you started we extracted the <code>activerecord-cachedb-adapter</code> and <a href="http://github.com/nicksieger/activerecord-cachedb-adapter">put it on Github</a> for you to use as a template.</p>
<p>The 1.0.0 release had over 200 commits poured into it and lots of great help from the community. Thanks to David Kellum, Dmitry Denisov, Dwayne Litzenberger, Gregor Schmidt, James Walker, John Duff, Joshua Suggs, Nicholas J Kreucher, Peter Donald, Geoff Longman, Uwe Kubosch, Youhei Kondou, Michael Pitman, Alex B, and Ryan Bell for their contributions to this release.</p>
<p>Enjoy!</p>Nick Siegerurn:uuid:4c6d6645-1832-4ed6-b947-51f55231f41f2010-08-30T17:12:07+00:002010-11-22T18:03:42+00:00JRuby at JavaZone 2010<p>I’m pleased to be able to return to Oslo for JavaZone 2010. Whether you’re checking out JRuby for the first time or a veteran JRuby user, I’ll have something for you! And if I don’t, I encourage you to come badger me after the talk is finished.</p>
<h3><a href="http://javazone.no/incogito10/events/JavaZone%202010/sessions/JRuby:%20Now%20With%20More%20J!">JRuby: Now With More J!</a></h3>
<p>Additionally, if you’re interested in meeting up for some JRuby discussion next week in Oslo, do drop me a note at the address in the upper right.</p>Nick Siegerurn:uuid:055dd055-5fd2-4b4b-ab36-41f8063966272010-08-30T17:06:52+00:002010-11-22T18:03:43+00:00Deploying, Monitoring and Troubleshooting Rails on JRuby<p>I am pleased that my Engine Yard webinar on JRuby and deployment is available for general viewing. While the JRuby deployment story is still evolving and maturing, and the 60 minute time frame is too short to cover the issues in depth, I hope you’ll find the content at least gives you some ideas or directions to look.</p>
<p>As always, feel free to contact me with any questions!</p>
<p><iframe src="http://player.vimeo.com/video/14435288" width="400" height="300" frameborder="0"></iframe><p><a href="http://vimeo.com/14435288">Deploying, Monitoring and Troubleshooting Rails on the JVM with JRuby</a> from <a href="http://vimeo.com/engineyard">Engine Yard</a> on <a href="http://vimeo.com">Vimeo</a>.</p></p>Nick Siegerurn:uuid:a2ff03a8-5c6c-4bf0-b000-8a169b441be82010-04-06T17:11:17+00:002010-11-22T18:03:43+00:00Warbler 1.0<p>It’s past due time to “carry the 1” over and roll over to a 1.0 version of <a href="http://caldersphere.rubyforge.org/warbler/">Warbler</a>. This time around, the changes in the codebase are significant enough that I hope you’ll find many past usability issues resolved.</p>
<h2>Assemble in-place</h2>
<p>The biggest change is that Warbler now creates a war file in place, without an intermediate copy-to-assemble step. Warbler does this using the <code>rubyzip</code> gem, or alternatively using a small Java extension when run under JRuby 1.5 or greater. This should reduce processing and confusion due to the extra copy, which can sometimes get out of sync. The downside is that Warbler cannot be used easily for exploded directory development, though you can always create the war file and unpack it to a staging area. </p>
<h2>Simpler extension</h2>
<p>Warbler also underwent an internal refactoring that should make extending it much easier. Here’s how you add Warbler tasks to your <code>Rakefile</code>:</p>
<div class="typocode"><pre><code class="typocode_ruby "><span class="ident">require</span> <span class="punct">'</span><span class="string">warbler</span><span class="punct">'</span>
<span class="constant">Warbler</span><span class="punct">::</span><span class="constant">Task</span><span class="punct">.</span><span class="ident">new</span></code></pre></div>
<p>In versions prior to 1.0, if there were deploy steps that created new files that didn’t exist at the time the <code>Rakefile</code> was loaded (such as what the <code>asset:packager:build_all</code> task does in the <a href="http://synthesis.sbecker.net/pages/asset_packager">asset_packager</a> plugin), it was tricky to get Warbler to recognize them. No longer -- now the expected Rake configuration should do the trick.</p>
<div class="typocode"><pre><code class="typocode_ruby "><span class="ident">require</span> <span class="punct">'</span><span class="string">warbler</span><span class="punct">'</span>
<span class="constant">Warbler</span><span class="punct">::</span><span class="constant">Task</span><span class="punct">.</span><span class="ident">new</span>
<span class="ident">task</span> <span class="symbol">:war</span> <span class="punct">=></span> <span class="punct">"</span><span class="string">asset:packager:build_all</span><span class="punct">"</span></code></pre></div>
<h2>Bundler support</h2>
<p>Another exciting development in the Ruby development world is <a href="http://gembundler.com/">Bundler</a>, and Warbler 1.0 supports packaging your bundled gems with it. Warbler even creates a <code>.bundle/environment.rb</code> file inside the war file that loads the gems from relative paths to where Warbler puts the gems in the war file.</p>
<h2>More configuration</h2>
<p>There are a number of new configuration options, so <a href="http://github.com/nicksieger/warbler/blob/master/warble.rb">check out the new configuration</a> and see if any are useful to you.</p>
<ul>
<li><code>config.gem_home</code> allows you to control the path inside the war file where Warbler will pack your application’s gems. For use with older versions of Bundler or other custom gem vendoring schemes.</li>
<li><code>config.webinf_files</code> is a file list that can contain multiple files, XML or otherwise. If the files named in this list have <code>.erb</code> extensions, they will be expanded in the same manner as <code>web.xml</code>.</li>
</ul>
<h2>Rails 3 support</h2>
<p><a href="http://jruby-rack.kenai.com/">JRuby-Rack</a>, the servlet adapter component bundled by Warbler, also received a version bump, and there are no longer any Java libraries included in the Warbler gem, so the two components can be versioned independently. With the release of both Warbler 1.0 and JRuby-Rack 0.9.7, Rails 3 applications can be warbled and deployed seamlessly, often without any additional configuration.</p>
<p>Please continue to send feedback to the <a href="http://xircles.codehaus.org/lists/user@jruby.codehaus.org">JRuby mailing list</a> or the <a href="http://kenai.com/jira/browse/WARBLER">Warbler bug tracker</a>. Enjoy!</p>Nick Siegerurn:uuid:603837d6-55bf-4e03-8fec-4d2db26c002e2010-02-24T03:58:00+00:002010-11-22T18:03:45+00:00JRuby and Rails 3, Sitting in a Tree<h2>Synopsis</h2>
<pre><code>jruby -S rails new myapp -m http://jruby.org/rails3.rb
</code></pre>
<p>When creating your Rails 3 application, just add the JRuby-specific template (<code>-m http://jruby.org/rails3.rb</code>).</p>
<h2>Details</h2>
<pre><code>$ jruby -S gem install rails --pre --no-rdoc --no-ri
Due to a rubygems bug, you must uninstall all older versions of bundler for 0.9 to work
Successfully installed i18n-0.3.3
Successfully installed tzinfo-0.3.16
Successfully installed builder-2.1.2
Successfully installed memcache-client-1.7.8
Successfully installed activesupport-3.0.0.beta
Successfully installed activemodel-3.0.0.beta
Successfully installed rack-1.1.0
Successfully installed rack-test-0.5.3
Successfully installed rack-mount-0.4.7
Successfully installed abstract-1.0.0
Successfully installed erubis-2.6.5
Successfully installed actionpack-3.0.0.beta
Successfully installed arel-0.2.1
Successfully installed activerecord-3.0.0.beta
Successfully installed activeresource-3.0.0.beta
Successfully installed mime-types-1.16
Successfully installed mail-2.1.3
Successfully installed text-hyphen-1.0.0
Successfully installed text-format-1.0.0
Successfully installed actionmailer-3.0.0.beta
Successfully installed thor-0.13.3
Successfully installed railties-3.0.0.beta
Successfully installed bundler-0.9.7
Successfully installed rails-3.0.0.beta
24 gems installed
</code></pre>
<h3>And:</h3>
<pre><code>$ jruby -S gem install activerecord-jdbcsqlite3-adapter --no-rdoc --no-ri
Successfully installed activerecord-jdbc-adapter-0.9.3-java
Successfully installed jdbc-sqlite3-3.6.3.054
Successfully installed activerecord-jdbcsqlite3-adapter-0.9.3-java
3 gems installed
</code></pre>
<h3>Finally:</h3>
<pre><code>$ jruby -S rails new myapp -m http://jruby.org/rails3.rb
create
...(app creation)...
apply http://jruby.org/rails3.rb
apply http://jruby.org/templates/default.rb
gsub Gemfile
run jruby script/rails generate jdbc from "."
...(warnings omitted)...
exist
create config/initializers/jdbc.rb
create lib/tasks/jdbc.rake
$ cd myapp
$ jruby script/rails server
...(warnings omitted)...
=> Booting WEBrick
=> Rails 3.0.0.beta application starting in development on http://0.0.0.0:3000
=> Call with -d to detach
=> Ctrl-C to shutdown server
[2010-02-23 19:44:26] INFO WEBrick 1.3.1
[2010-02-23 19:44:26] INFO ruby 1.8.7 (2010-02-23) [java]
[2010-02-23 19:44:26] INFO WEBrick::HTTPServer#start: pid=16449 port=3000
</code></pre>
<p><img src="http://img.skitch.com/20100224-eik9e957x7uu8k5x8y4xgt9jes.jpg" alt="rails-welcome"/></p>
<h2>Recap</h2>
<p>You’ll have best results with <a href="http://ci.jruby.org/snapshots">JRuby 1.5 snapshots</a>, which include RubyGems 1.3.6. JRuby 1.5 final is coming soon. Also, <a href="http://rubyforge.org/forum/forum.php?forum_id=36489">the new <code>activerecord-jdbc-adapter</code> 0.9.3 release</a> is required for Rails 3 compatibility.</p>
<p>The Rails experience on JRuby continues to get better.</p>Nick Siegerurn:uuid:32ea8753-bf86-4fe8-bec2-4b2f432512fe2009-04-11T04:10:51+00:002010-11-22T18:06:58+00:00JRuby on Google AppEngine: First Impressions<p>I was surprised by <a href="http://googleappengine.blogspot.com/2009/04/seriously-this-time-new-language-on-app.html">Tuesday’s announcements</a> as much as anyone else. <a href="http://olabini.com/blog/2009/04/jruby-on-rails-on-google-app-engine/">Ola keeps secrets well</a>. He sent me a pull request for <a href="http://jruby-rack.kenai.com/pages/Home">jruby-rack</a> just last week mentioning “some restrictive environments where you can’t start threads”. I didn’t blink, and instead just merged his patch.</p>
<p><img src="http://rubyonrails.org/images/rails.png" alt="rails"/>
<img src="http://2.bp.blogspot.com/_dLfQMJsmsaI/SdvwPx8hz5I/AAAAAAAAACY/I_DEfn6nQjc/s320/ae_gwt_java.png" alt="java-gae"/></p>
<p>Despite the surprise news, it turns out my timing wasn’t bad. <a href="http://twitter.com/nicksieger/status/1189629742">Just a couple of weeks ago I was experimenting</a> with the Python version of AppEngine, just to see what the fuss is all about. Even though Google’s had its <a href="http://radar.oreilly.com/archives/2008/04/is-google-app-engine-a-lockin.html">share</a> of <a href="http://www.tbray.org/ongoing/When/200x/2008/04/09/Google-Users-API">criticism</a> for building a platform that is difficult for developers to leave, the lock-in aspect didn’t bother me. I’m a pragmatist first, and I believe that we as developers are the only ones locking ourselves to a platform. We have a choice, after all. And look at <a href="http://www.nytimes.com/2009/04/05/fashion/05iphone.html">all the developers willfully rushing</a> to develop Cocoa applications for the iPhone. The fact that their code is not useful on any other device isn’t stopping them.</p>
<p>The thing with AppEngine is that it’s a unique platform all unto itself. That may seem brutally obvious, but the point seems to be lost in all the frenzy surrounding the Run-Rails-Struts-Spring-Groovy-Grails-Lift-You-Name-It-Framework on AppEngine this week. I’m not saying it’s a bad idea to try to run Rails on AppEngine; quite the contrary. I’m saying you need to be honest about the trade-offs and constraints. And in the case of Ruby and Rails, boy are there a bunch of them:</p>
<ul>
<li>No regular <code>net/http</code>, <code>restclient</code>, <code>ActiveResource</code> usage. Google has a URL fetch library, and has hooked up Java’s <code>HttpURLConnection</code> to it, but none of the Ruby URL-fetching libraries use it.</li>
<li>No ActiveRecord. ‘Nuff said. For some folks, that’s a welcome change, but wrapping your head around AppEngine’s BigTable-backed data store takes some thought. You just can’t view it like a SQL engine.</li>
<li>No RMagick/ImageScience/attachment_fu. No <a href="/articles/2008/03/27/imagevoodoo-0-1-released">ImageVoodoo</a> even (no javax.image APIs). Google has it’s own image manipulation API.</li>
<li>Startup/first request processing time is currently an issue. It’s not clear yet how long Google keeps JVMs warm, so if your application is idle, the first few hits to it return 500 errors. I can only assume Google has a plan to address this.</li>
<li>Crypto. Although java.security and javax.crypto APIs are apparently <a href="http://code.google.com/appengine/docs/java/jrewhitelist.html">whitelisted</a>, I haven’t had time to figure out how to leverage them. JRuby’s jruby-openssl gem does not work, which means things like <code>digest</code> aren’t available. That’s currently a blocker for Rails’ cookie session store.</li>
<li>1000-files limit per application. In order to work around this, I ended up <a href="/articles/2009/01/10/jruby-1-1-6-gems-in-a-jar">jarring up all the Rails gems</a> when deploying a Rails application.</li>
</ul>
<p>These are just a sampling of some of the problems you’re dealing with on the AppEngine frontier. They’re all solvable; it will take a little time and BST (blood, sweat and tears). The point is you can’t expect a Rails application on AppEngine to behave like all the Rails applications you’ve written previously.</p>
<p>In return for your troubles, you get the AppEngine value proposition, which is actually attractive in a lot of ways: Google runs the platform. You don’t have to worry about it. Transparent scaling, monitoring, logging, everything below your application code is taken care of. Single-step deployment, with application versioning and rollback. Scalable services: BigTable storage, memcached, scheduled tasks. My friend <a href="http://googleappengine.blogspot.com/2009/02/best-buys-giftag-on-app-engine.html">Curt Thompson of Best Buy’s Giftag.com</a> talks about how they leverage AppEngine for a non-toy application. (Curt also helped me get my <a href="http://nicksieger-notes.appspot.com/">Python AppEngine experiment</a> up and running.)</p>
<p>In the end, I’m still extremely excited about the prospect of using JRuby and Rails on AppEngine, and can’t wait to see what people build with these tools. If you want a little head start, you can check out the first Rails application I deployed, <a href="http://jruby-rack.appspot.com/">jruby-rack.appspot.com</a>. The “application environment” page is the main dynamic action in the app, which just enumerates a bunch of request and system environment properties so you can get a feel for how things are set up in the AppEngine Java environment. The source code for the application is linked from the front page. Note that the app was deployed with JRuby trunk and <a href="http://kenai.com/projects/jruby-rack/lists/talk/archive/2009-04/message/0">JRuby-Rack 0.9.4</a>; Warbler is not yet using these components but you can build them yourself, drop them in and try them. We’ll be updating JRuby, Warbler and other tools soon to make this process more seamless soon. Stay tuned!</p>Nick Siegerurn:uuid:9fe84534-3a40-40e8-8626-a15bb05d74b42007-03-16T16:55:00+00:002010-11-22T18:06:59+00:00JRuby on Rails: Integration Plugin Goes 1.0<p>On the heels of my last post, Robert <a href="http://rubyforge.org/pipermail/jruby-extras-devel/2007-March/000432.html">announced the 1.0 release of Rails Integration</a>, the bits that allow JRuby on Rails to be run out of a Java web archive (war). If you have any interest at all in trying out JRuby on Rails, do yourself a favor and <a href="http://www.headius.com/jrubywiki/index.php/Rails_Integration">try out the integration bits</a>. Even though this is 1.0, we’re still moving rapidly and would appreciate any and all feedback. (And Robert is doing his best to keep up with changes in core.)</p>
<p>Related to this, Stuart Halloway <a href="http://www.relevancellc.com/2007/3/14/the-j-plugin-existing-rails-apps-on-jruby">recently announced his J plugin</a> which is a drop-in collection of Rake tasks that bridge the inherent differences between Rails running on C Ruby vs. JRuby. We still have some work to do in some areas, such as database driver configuration, test database bootstrapping and launching unit tests. For example, instead of the <a href="http://dev.rubyonrails.org/svn/rails/branches/1-2-stable/railties/lib/tasks/databases.rake">big, ugly, database-specific case statement that’s in Rails’ databases.rake today</a>:</p>
<div class="typocode"><pre><code class="typocode_ruby "><span class="ident">desc</span> <span class="punct">"</span><span class="string">Recreate the test databases from the development structure</span><span class="punct">"</span>
<span class="ident">task</span> <span class="symbol">:clone_structure</span> <span class="punct">=></span> <span class="punct">[</span> <span class="punct">"</span><span class="string">db:structure:dump</span><span class="punct">",</span> <span class="punct">"</span><span class="string">db:test:purge</span><span class="punct">"</span> <span class="punct">]</span> <span class="keyword">do</span>
<span class="ident">abcs</span> <span class="punct">=</span> <span class="constant">ActiveRecord</span><span class="punct">::</span><span class="constant">Base</span><span class="punct">.</span><span class="ident">configurations</span>
<span class="keyword">case</span> <span class="ident">abcs</span><span class="punct">["</span><span class="string">test</span><span class="punct">"]["</span><span class="string">adapter</span><span class="punct">"]</span>
<span class="keyword">when</span> <span class="punct">"</span><span class="string">mysql</span><span class="punct">"</span>
<span class="constant">ActiveRecord</span><span class="punct">::</span><span class="constant">Base</span><span class="punct">.</span><span class="ident">establish_connection</span><span class="punct">(</span><span class="symbol">:test</span><span class="punct">)</span>
<span class="constant">ActiveRecord</span><span class="punct">::</span><span class="constant">Base</span><span class="punct">.</span><span class="ident">connection</span><span class="punct">.</span><span class="ident">execute</span><span class="punct">('</span><span class="string">SET foreign_key_checks = 0</span><span class="punct">')</span>
<span class="constant">IO</span><span class="punct">.</span><span class="ident">readlines</span><span class="punct">("</span><span class="string">db/<span class="expr">#{RAILS_ENV}</span>_structure.sql</span><span class="punct">").</span><span class="ident">join</span><span class="punct">.</span><span class="ident">split</span><span class="punct">("</span><span class="string">
</span><span class="punct">").</span><span class="ident">each</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">table</span><span class="punct">|</span>
<span class="constant">ActiveRecord</span><span class="punct">::</span><span class="constant">Base</span><span class="punct">.</span><span class="ident">connection</span><span class="punct">.</span><span class="ident">execute</span><span class="punct">(</span><span class="ident">table</span><span class="punct">)</span>
<span class="keyword">end</span>
<span class="keyword">when</span> <span class="punct">"</span><span class="string">postgresql</span><span class="punct">"</span>
<span class="constant">ENV</span><span class="punct">['</span><span class="string">PGHOST</span><span class="punct">']</span> <span class="punct">=</span> <span class="ident">abcs</span><span class="punct">["</span><span class="string">test</span><span class="punct">"]["</span><span class="string">host</span><span class="punct">"]</span> <span class="keyword">if</span> <span class="ident">abcs</span><span class="punct">["</span><span class="string">test</span><span class="punct">"]["</span><span class="string">host</span><span class="punct">"]</span>
<span class="constant">ENV</span><span class="punct">['</span><span class="string">PGPORT</span><span class="punct">']</span> <span class="punct">=</span> <span class="ident">abcs</span><span class="punct">["</span><span class="string">test</span><span class="punct">"]["</span><span class="string">port</span><span class="punct">"].</span><span class="ident">to_s</span> <span class="keyword">if</span> <span class="ident">abcs</span><span class="punct">["</span><span class="string">test</span><span class="punct">"]["</span><span class="string">port</span><span class="punct">"]</span>
<span class="constant">ENV</span><span class="punct">['</span><span class="string">PGPASSWORD</span><span class="punct">']</span> <span class="punct">=</span> <span class="ident">abcs</span><span class="punct">["</span><span class="string">test</span><span class="punct">"]["</span><span class="string">password</span><span class="punct">"].</span><span class="ident">to_s</span> <span class="keyword">if</span> <span class="ident">abcs</span><span class="punct">["</span><span class="string">test</span><span class="punct">"]["</span><span class="string">password</span><span class="punct">"]</span>
`<span class="ident">psql</span> <span class="punct">-</span><span class="constant">U</span> <span class="punct">"</span><span class="string"><span class="expr">#{abcs["test"]["username"]}</span></span><span class="punct">"</span> <span class="punct">-</span><span class="ident">f</span> <span class="ident">db</span><span class="punct">/</span><span class="comment">#{RAILS_ENV}_structure.sql #{abcs["test"]["database"]}`</span>
<span class="keyword">when</span> <span class="punct">"</span><span class="string">sqlite</span><span class="punct">",</span> <span class="punct">"</span><span class="string">sqlite3</span><span class="punct">"</span>
<span class="ident">dbfile</span> <span class="punct">=</span> <span class="ident">abcs</span><span class="punct">["</span><span class="string">test</span><span class="punct">"]["</span><span class="string">database</span><span class="punct">"]</span> <span class="punct">||</span> <span class="ident">abcs</span><span class="punct">["</span><span class="string">test</span><span class="punct">"]["</span><span class="string">dbfile</span><span class="punct">"]</span>
`<span class="comment">#{abcs["test"]["adapter"]} #{dbfile} < db/#{RAILS_ENV}_structure.sql`</span>
<span class="keyword">when</span> <span class="punct">"</span><span class="string">sqlserver</span><span class="punct">"</span>
`<span class="ident">osql</span> <span class="punct">-</span><span class="constant">E</span> <span class="punct">-</span><span class="constant">S</span> <span class="comment">#{abcs["test"]["host"]} -d #{abcs["test"]["database"]} -i db\#{RAILS_ENV}_structure.sql`</span>
<span class="keyword">when</span> <span class="punct">"</span><span class="string">oci</span><span class="punct">",</span> <span class="punct">"</span><span class="string">oracle</span><span class="punct">"</span>
<span class="constant">ActiveRecord</span><span class="punct">::</span><span class="constant">Base</span><span class="punct">.</span><span class="ident">establish_connection</span><span class="punct">(</span><span class="symbol">:test</span><span class="punct">)</span>
<span class="constant">IO</span><span class="punct">.</span><span class="ident">readlines</span><span class="punct">("</span><span class="string">db/<span class="expr">#{RAILS_ENV}</span>_structure.sql</span><span class="punct">").</span><span class="ident">join</span><span class="punct">.</span><span class="ident">split</span><span class="punct">("</span><span class="string">;
</span><span class="punct">").</span><span class="ident">each</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">ddl</span><span class="punct">|</span>
<span class="constant">ActiveRecord</span><span class="punct">::</span><span class="constant">Base</span><span class="punct">.</span><span class="ident">connection</span><span class="punct">.</span><span class="ident">execute</span><span class="punct">(</span><span class="ident">ddl</span><span class="punct">)</span>
<span class="keyword">end</span>
<span class="keyword">when</span> <span class="punct">"</span><span class="string">firebird</span><span class="punct">"</span>
<span class="ident">set_firebird_env</span><span class="punct">(</span><span class="ident">abcs</span><span class="punct">["</span><span class="string">test</span><span class="punct">"])</span>
<span class="ident">db_string</span> <span class="punct">=</span> <span class="ident">firebird_db_string</span><span class="punct">(</span><span class="ident">abcs</span><span class="punct">["</span><span class="string">test</span><span class="punct">"])</span>
<span class="ident">sh</span> <span class="punct">"</span><span class="string">isql -i db/<span class="expr">#{RAILS_ENV}</span>_structure.sql <span class="expr">#{db_string}</span></span><span class="punct">"</span>
<span class="keyword">else</span>
<span class="keyword">raise</span> <span class="punct">"</span><span class="string">Task not supported by '<span class="expr">#{abcs["test"]["adapter"]}</span>'</span><span class="punct">"</span>
<span class="keyword">end</span>
<span class="keyword">end</span></code></pre></div>
<p>we can use migrations to create the test database:</p>
<div class="typocode"><pre><code class="typocode_ruby "><span class="ident">desc</span> <span class="punct">"</span><span class="string">Recreate the test databases from migrations</span><span class="punct">"</span>
<span class="ident">task</span> <span class="symbol">:migrate_test_db</span> <span class="keyword">do</span>
<span class="constant">ActiveRecord</span><span class="punct">::</span><span class="constant">Base</span><span class="punct">.</span><span class="ident">establish_connection</span><span class="punct">(</span><span class="constant">ActiveRecord</span><span class="punct">::</span><span class="constant">Base</span><span class="punct">.</span><span class="ident">configurations</span><span class="punct">['</span><span class="string">test</span><span class="punct">'])</span>
<span class="constant">ActiveRecord</span><span class="punct">::</span><span class="constant">Schema</span><span class="punct">.</span><span class="ident">verbose</span> <span class="punct">=</span> <span class="ident">t</span><span class="punct">.</span><span class="ident">application</span><span class="punct">.</span><span class="ident">options</span><span class="punct">.</span><span class="ident">trace</span>
<span class="constant">ActiveRecord</span><span class="punct">::</span><span class="constant">Migrator</span><span class="punct">.</span><span class="ident">migrate</span><span class="punct">("</span><span class="string">db/migrate/</span><span class="punct">")</span>
<span class="keyword">end</span></code></pre></div>
<p>Over time, I hope to see all these efforts coalesce and make the Rails developer experience virtually identical on either interpreter. What would be most excellent is to eventually push some of these improvements back to the Rails core.</p>Nick Siegerurn:uuid:091b1464-16fe-49ee-9d4b-ce18ddf2da0d2006-05-15T03:12:00+00:002010-11-22T18:06:59+00:00JRuby on Rails and ActiveRecord on JDBC<p><a href="http://www.bloglines.com/blog/ThomasEEnebo?id=16">Tom</a> and <a href="http://headius.blogspot.com/2006/05/and-they-said-jruby-was-dead.html">Charlie</a> have just experienced what can only be described as a watershed moment in the grand scheme of dynamic languages on the JVM. The Rails experience may soon be visiting a Java application server near you! Even though JRuby will be in perpetual catch-up mode with C Ruby, Tom and Charlie and the rest of the JRuby contributors have shown incredible perseverance in tracking the Ruby language despite <em>the lack of any formal specification</em>. Maybe Rails will never be mainstream, but the possibilities just got a whole lot more interesting. I agree with <a href="http://jroller.com/page/obie?entry=jruby_on_rails_is_born">Obie</a> that this could be a game-changer.</p>
<p>Now, a few comments about the ActiveRecord JDBC adapter. This code can still be considered alpha quality at best. It’s awesome that Tom and Charlie will be able to demo a top-to-bottom, working Rails app on JRuby, but don’t jump to conclusions yet that this will be anything like a write-once, deploy-to-any-database kind of experience. But you didn’t think it would, did you? We all learned that about Java a long time ago, right?</p>
<p>You can <a href="http://svn.caldersphere.net/svn/main/activerecord-jdbc/trunk/">check out the code here</a>. At the moment, I’ve only tried it with MySQL. Most of the problems with it come from the lossy mapping from ActiveRecord’s abstraction of the database to JDBC’s. (Although I suspect as more JDBC drivers are tried that there will eventually be compatibility issues with different implementations of the JDBC spec.)</p>
<p>Probably the thorniest issue is the one of type conversion. ActiveRecord has a fairly simple notion of types: <code>:string, :text, :integer, :float, :datetime</code> etc. Compare this to <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/sql/Types.html">JDBC’s</a>. What a mess! Right now there are arrays of <code>proc</code>s for each AR type that try to guess the best JDBC type to use. This will certainly need improvement to become a more robust solution.</p>
<p>Probably the most promising approach may be to create a patch that refactors much of the AR adapters’ type conversion methods into separate modules that could be included into instances of the JDBC adapter depending on the underlying database. Then the JDBC types wouldn’t be needed at all -- the existing AR database metadata could be reused. Presumably this would require some petitioning of the Rails core team to accept the changes even though the changes don’t buy AR itself any additional flexibility.</p>
<p>If you have a chance to try out the code or can think of any additional tricks that would help the ActiveRecord JDBC implementation along, let me know!</p>Nick Siegerurn:uuid:a88e00d4-56b6-4b75-95e9-4e21e6b0387a2007-09-04T02:48:40+00:002010-11-22T18:06:59+00:00Warbler, A Little Birdie To Introduce Your Rails App To Java<p>This week I was working on integrating the latest <a href="http://www.bloglines.com/blog/ThomasEEnebo?id=35">JRuby 1.0.1</a> and <a href="http://rubyforge.org/frs/shownotes.php?release_id=14048">Goldspike 1.3</a> releases into our environment, when my frustration hit a fever pitch.</p>
<p>See, I had always thought that the .war packaging side of Goldspike was a little clunky and
un-ruby-like, but I didn’t see a clear path to fixing it. I had heard little complaints about it here
and there: the little configuration DSL didn’t give you enough control or wasn’t documented well
enough; the fact that it downloads libraries from the internet during assembly (convenient, but not
safe or reproducible for production deployments).</p>
<p>Also, in my own opinion it took the wrong approach to packaging Rails in a .war file. It puts the
Rails application directory structure into the root of the .war file where any web server or Java
application server might mistakenly serve up your code as static content. The Java .war file spec has
this special directory called <code>WEB-INF</code> expressly for the purpose of hiding that stuff away, so why
not use it?</p>
<p>And then, suddenly Goldspike was packaging up my entire Rails application directory, .svn directories
and everything. So I set out to fix this once and for all.</p>
<p>And so I present <a href="http://caldersphere.rubyforge.org/warbler/">Warbler</a>. A little bird who chirpily steps up to the task of assembling your
Rails application into a Java Web Archive (.war). Here, get it:</p>
<pre><code>gem install warbler
</code></pre>
<p>And then, in the top directory of your Rails application,</p>
<pre><code>warble
</code></pre>
<p>Those two steps are all it takes to make a .war file, including your application and recent versions
of JRuby and Goldspike, that’s deployable to your <a href="https://glassfish.dev.java.net/">favorite Java application server</a>.</p>
<p>There are a number of points about Warbler worth mentioning.</p>
<h3>Does one thing, well</h3>
<p>Warbler only packages, and doesn’t care about anything else, like how to dispatch servlet requests to
Rails. This will allow for more runtime servlet binding mechanisms to take advantage of Warbler in
the future.</p>
<h3>Fast and lightweight</h3>
<p>50% less code than the Goldspike packaging plugin, yet does the job quickly and efficiently.</p>
<h3>Sane defaults</h3>
<p>Warbler only packages code that you need to run the application, omitting database migrations and
tests. If your application is self-sufficient (no external dependencies), then the out-of-the-box
configuration will probably work for you. Public HTML/images/javascript/stylesheets go in the root of
the webapp, where Java webservers expect them to be.</p>
<h3>Documented, flexible configuration</h3>
<p>Need to customize your configuration? Run <code>warble config</code> and edit <code>config/warble.rb</code>. All the
options are there, commented and documented.</p>
<p>Need to change out the bundled JRuby/Goldspike versions? <code>warble pluginize</code> makes a copy of Warbler
in the <code>vendor/plugins</code> area of your application, allowing you to change the .jar files in the
<code>vendor/plugins/warbler-0.9/lib</code> directory. Warbler then makes his nest in your project’s list of
rake tasks (as <code>rake -T | grep war</code> shows)</p>
<pre><code>rake war # Create trunk.war
rake war:app # Copy all application files into the .war
rake war:clean # Clean up the .war file and the staging area
rake war:gems # Unpack all gems into WEB-INF/gems
rake war:jar # Run the jar command to create the .war
rake war:java_libs # Copy all java libraries into the .war
rake war:public # Copy all public HTML files to the root of the .war
rake war:webxml # Generate a web.xml file for the webapp
</code></pre>
<p>Warbler even omits himself in the .war file produced when running in plugin mode, since you won’t
need him at runtime. It’s the little details that matter.</p>
<p>Give him a try and let me know if it makes your life deploying Rails applications to JRuby on Java appservers easier!</p>Nick Siegerurn:uuid:bfda082f-fa26-41d8-aa16-fc07b41aba352007-10-25T03:36:00+00:002010-11-22T18:07:00+00:00JRuby on Rails: Fast Enough<p>People have been asking for a while how fast JRuby runs Rails. (Of course, “fast” has always been a <a href="http://www.joelonsoftware.com/items/2006/09/12.html">relative term</a>.) We haven’t been quick to answer the question, because frankly we didn’t know. We hadn’t been building real Rails applications on JRuby ourselves yet, and there was no definitive word from the crowd either.</p>
<p>Recently, several guys from <a href="http://studios.thoughtworks.com/rubyworks">ThoughtWorks</a> have been working on a <a href="http://tw-commons.rubyforge.org/svn/petstore/trunk/">Rails petstore</a> application and benchmark to get to the heart of the matter. <a href="http://www.nabble.com/forum/Search.jtp?forum=14106&local=y&query=petstore">Discussion has been heated</a> on the JRuby mailing list, but results have not been conclusive yet.</p>
<p>In the project I’m working on, we’ve <a href="http://blog.nicksieger.com/articles/2007/10/06/railsconf-europe-hydra">committed to using and deploying on JRuby</a>. Eventually we were going to reach the point where we’d need to find out how well our application runs. So today I began running a simple single request benchmark on a relatively busy page. The numbers turned out to be rather surprising:</p>
<p><img src="/files/jr-requests.png" alt="Requests" title="Requests"/></p>
<p><img src="/files/jr-average.png" alt="Average" title="Average"/></p>
<p>(The <a href="http://spreadsheets.google.com/pub?key=pGobleZnKsdI1zW38xpNaaw">raw data is available here</a>.)</p>
<p>Now, MRI (C Ruby) will always run about the same speed no matter how many runs you give it, but it’s well known that the JVM <a href="http://www.javaworld.com/javaworld/javaqa/2003-04/01-qa-0411-hotspot.html">needs time to warm up</a>. And indeed it does; after 250 iterations, Mongrel running on JRuby finally surpasses MRI. The JRuby/Goldspike/Glassfish combo comes close as well.</p>
<p>Some details about the setup:</p>
<ul>
<li>I ran the tests on my MacBook Pro Core 2 Duo 2.4 GHz. I didn’t disable one of the cores for the tests, which means that JRuby has an advantage over MRI because it can use both (native threads at work). However, the test script ran the requests serially, which means that the advantage was minimal.</li>
<li>The application is indeed of the <a href="http://blog.nicksieger.com/articles/2007/10/06/railsconf-europe-hydra">“hydra”</a> variety; the setup is nearly identical to the second diagram on that page. So a single request is passing through <strong>not one, but two</strong> Rails applications in addition to touching the database. It rendered an HTML ERb view with data from an ActiveResource-accessed RESTful service. The applications are based on Rails 1.2.3.</li>
<li>MRI version is using Ruby 1.8.6 and Mongrel 1.0.1.</li>
<li>JRuby Mongrel is also version 1.0.1 (<a href="http://jxh.bingodisk.com/bingo/public/Hackdays/JRuby/">details on installing it here</a>)</li>
<li>JRuby on Glassfish used Glassfish 2 and Goldspike 1.4, deployed in war files via <a href="http://caldersphere.rubyforge.org/warbler">Warbler</a>.</li>
<li>The two JRuby setups used JDK 1.5 and were tweaked to <a href="http://ola-bini.blogspot.com/2007/07/objectspace-to-have-or-not-to-have.html">disable ObjectSpace</a> and use the “server” VM (-server argument to the JVM).</li>
</ul>
<p>The main point I wish to make with these numbers is that JRuby performance is there today, and still has room to grow. There’s no longer any doubt in my mind. Yes, this is a simplistic application benchmark run on a developer’s machine, but it’s a real application. The test may not be exacting in precision, but I see enough in the numbers to believe that this will be replicable to production environments. The plot thickens!</p>