Nick Sieger: Tag rails tag:blog.nicksieger.com,2005:Typo Typo 2010-11-22T18:03:42+00:00 Nick Sieger urn:uuid:8f70150f-ec57-4646-afaa-c3e07b6df7c3 2010-10-14T15:25:51+00:00 2010-11-22T18:03:42+00:00 activerecord-jdbc-adapter 1.0.0 <p>Just a quick note that <code>activerecord-jdbc-adapter</code> has finally hit 1&#46;0&#46;0&#46; 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>&#46;</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&#46; 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&#46; 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>&#46;</p> <p>This release promises superb compatibility with Rails 3&#46; We now have the ActiveRecord test suite <a href="http://ci.jruby.org/view/Rails">running in CI</a> and the 1&#46;0&#46;0 release is 100% green when run on MySQL&#46; (SQLite3 is right behind with just 13 failures, and we hope to fix those soon&#46;)</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 &amp;&amp; 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&#46;0&#46;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&#46; 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&#46;</p> <p>The 1&#46;0&#46;0 release had over 200 commits poured into it and lots of great help from the community&#46; 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&#46;</p> <p>Enjoy!</p> Nick Sieger urn:uuid:055dd055-5fd2-4b4b-ab36-41f806396627 2010-08-30T17:06:52+00:00 2010-11-22T18:03:43+00:00 Deploying, Monitoring and Troubleshooting Rails on JRuby <p>I am pleased that my Engine Yard webinar on JRuby and deployment is available for general viewing&#46; 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&#8217;ll find the content at least gives you some ideas or directions to look&#46;</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>&#46;</p></p> Nick Sieger urn:uuid:603837d6-55bf-4e03-8fec-4d2db26c002e 2010-02-24T03:58:00+00:00 2010-11-22T18:03:45+00:00 JRuby 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&#45;specific template (<code>-m http://jruby.org/rails3.rb</code>)&#46;</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)... =&gt; Booting WEBrick =&gt; Rails 3.0.0.beta application starting in development on http://0.0.0.0:3000 =&gt; Call with -d to detach =&gt; 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&#8217;ll have best results with <a href="http://ci.jruby.org/snapshots">JRuby 1&#46;5 snapshots</a>, which include RubyGems 1&#46;3&#46;6&#46; JRuby 1&#46;5 final is coming soon&#46; Also, <a href="http://rubyforge.org/forum/forum.php?forum_id=36489">the new <code>activerecord-jdbc-adapter</code> 0&#46;9&#46;3 release</a> is required for Rails 3 compatibility&#46;</p> <p>The Rails experience on JRuby continues to get better&#46;</p> Nick Sieger urn:uuid:ab53b976-cff8-410d-8047-793abbb363a2 2007-05-23T05:51:36+00:00 2010-11-22T18:06:58+00:00 geekSessions I: Ruby on Rails: To Scale or Not to Scale <p>I was fortunate to be in town right after RailsConf and attended the inaugural <a href="http://www.geeksessions.com/">geekSessions</a> event on Rails scalibility&#46; The event went off without a hitch: it was well attended, City Club is a classy place, and there was decent food and an open bar&#46; I don&#8217;t know the SF geek/startup scene, but pretty much all of the few guys I know were there along with a ton of other folks&#46; My only complaint would have been to let it run at least 30 minutes longer&#46; Socializing was good too, but it seemed like the conversation was just getting started&#46;</p> <p>Here are some notes for you in my typical rapid&#45;fire style &#45;&#45; hope they&#8217;re useful to you&#46;</p> <h2>Ian McFarland</h2> <p>Case study: divine caroline</p> <p>Servers:</p> <ul> <li>Load balancer</li> <li>Apache + mongrel</li> <li>MySQL</li> <li>SOLR</li> </ul> <p>Ruby is slow&#46; Rails is slow&#46; Unoptimized app was slow &#45;&#45; 7 pages/sec with <code>ab</code>&#46; So how can Rails possibly be? 150 pv/s with a simple text render&#46; This formed a sort of upper&#45;bound, that ruled out fragment/action/partial caching, etc&#46; This brought the throughput to 3500 pv/s&#46; Except for page caching limitations:</p> <ul> <li>Cache coherency</li> <li>Writes are more expensive</li> <li>Page caching is not applicable to as many pages as you think</li> </ul> <p>But measure first&#46; Pivotal built a drop&#45;in page caching extension to deal with cache coherency issues (soon to be at http://rubyforge&#46;org/projects/pivotalrb)</p> <h2>Jason Hoffman</h2> <p>Jason somehow has the distinction of the first four commits in the Rails repository&#46; Joyent/TextDrive/Strongspace&#46;</p> <p>If your application is successful, you&#8217;re going to have a lot of machines&#46; What happens when you have 1000s of machines, 100s of TB, 4 locations, etc&#46; Is this really a <em>Rails</em> issue? In a typical Joyent setup, Rails is only one of 26+ processes on the server stack&#46; So scaling it really doesn&#8217;t mean much more than scaling any application&#46; Object creation in Ruby is fast, sockets and threads are slow&#46; So forget sockets and threads&#46;</p> <p>Instead, use DNS, load balancers, evented mongrels, JRuby/Java, DBMSes (not just RDBMS; LDAP, filesystem, etc&#46;), Rails process doing Rails only, static assets going through a static server, federate and separate as much as you can&#46;</p> <h2>Jeremy LaTrasse</h2> <p>Jeremy&#8217;s job is about safety nets; about knowing the underlying infrastructure&#46; Is the hardware/OS/stack important? Can you build safety nets around those so that you can spare cycles when you need to intrude into the system to troubleshoot?</p> <p>Twitter is in a unique position with the volume of traffic to be able to find some pretty tough bugs, like the recent <a href="http://dev.rubyonrails.org/changeset/6571">backtrace issue</a>&#46;</p> <h2>Bryan Cantrill</h2> <p>Measure first! Like Ian said&#46; Is software information? Or a machine? It&#8217;s both&#46; Nothing else in human existence can claim this&#46; 3 weeks after Bryan joined Sun, he was working with Jeff (ZFS architect) debugging an issue when Jeff retorted, &#8220;Does it bother you that none of this exists? It&#8217;s just a representation of some plastic and metal morass in a backroom&#8221; (slightly paraphrased)&#46;</p> <p>We&#8217;ve been living with bifurcated code &#45;&#45; &#8220;if DEBUG; print something&#8221; ad nauseum&#46; But this has a cost&#46; So dev code deviates from production code&#46; But we can&#8217;t get the data we want, where it matters, in production&#46; Bryan goes on to describe the aforementioned <a href="http://dev.rubyonrails.org/changeset/6571">backtrace issue</a> and how it saved Twitter 33% CPU&#46; So don&#8217;t pre&#45;optimize, but you&#8217;ve got to be prepared to go get the data&#46; In production&#46;</p> <h2>Q &amp; A</h2> <p><em>What&#8217;s the best way to move from one database to two databases (MySQL), when you scale past the volume of reads that overwhelms one?</em></p> <p><strong>Jason</strong> doesn&#8217;t like the replication approach, it&#8217;s not fault tolerant&#46; Reference to <a href="http://drnicwilliams.com/2007/04/12/magic-multi-connections-a-facility-in-rails-to-talk-to-more-than-one-database-at-a-time/">Dr Nic&#8217;s magic multi&#45;connections gem</a>&#46; Reference to <a href="http://revolutiononrails.blogspot.com/2007/04/plugin-release-actsasreadonlyable.html">acts_as_readonly</a>&#46; Don&#8217;t rely on things that are out of your control, start reading/writing to multiple locations, at the application level&#46; <strong>Jeremy</strong>: So do you want to be in the business of writing SQL or C extensions to Rails? What about <a href="http://freshmeat.net/projects/mysql_proxy/">MySQL proxy</a>? Seems ok, but I might not trust it in production&#46; <a href="http://jeremy.zawodny.com/mysql/mytop/" title="mytop - a top clone for MySQL">MyTop</a>/<a href="http://www.xaprb.com/blog/2006/07/02/innotop-mysql-innodb-monitor/">InnoTop</a> will tell you about your query volume&#46;</p> <p><em>Virtualization: 4 virtual servers w/ web servers on top of a single physical server? Why?</em></p> <p><strong>Jason</strong>: Free BSD 4&#46;9 on early pentium was the perfect balance of utilization&#46; 18 CPUs by 64G RAM with virtual servers gets us back to that level of utilization&#46; <strong>Bryan</strong>: Not all virtualization solutions are equivalent! (Solaris containers/zones plug&#46;)</p> <p><em>RDBMSes are not good for web applications? Why? Can you give some examples?</em></p> <p><strong>Jason</strong>: It depends on when you want to join&#46; When people are clicking, or pre&#45;assembled&#46; Look at your application and put the data together before people request it&#46; Why does YouTube need an RDBMS? It serves a file that people can comment on&#46;</p> <p>Mention of Dabble DB, ZFS, Jabber, Atom, Atom over Jabber, etc&#46; as ways of innovative ways of storing objects, data, etc&#46; GData/GCal most certainly does not store its Atom files in an RDBMS&#46;</p> <p><em>Sell Rails apps and have the customer deploy it? What options are available?</em></p> <p><strong>Ian</strong>: JRuby on Rails with a &#46;war file is an interesting approach&#46; <em>What operational issues/ways to help with scaling remote deployments?</em> <strong>Jeremy</strong>: Log files are the first line of defense&#46; <strong>Jason</strong>: Corporate IT are comfortable with Java&#46;</p> <p><em>The pessimist in me says that my servers are going to fall over after 5 users&#46; How can I be prepared/not be optimistic about a traffic spike?</em></p> <p><strong>Ian</strong>: Load test the crap out of the app&#46; Find out the horizontal scaling point&#46; Use solutions like S3 for images&#46; Make sure you can scale by throwing hardware at it&#46; Eventually single points of failure will overcome you (such as a single database), but you can wait until you get to that point before doing something about it&#46;</p> <p><strong>Jason</strong>: You can benchmark your processes, and get an idea of what they can do&#46; Most people that want to do something will be look at your stuff, and maybe signup&#46; So front&#45;load and optimize your signup process, possibly by taking it out of Rails&#46;</p> <p><strong>Jeremy</strong>: Conversations with Zed, DHH, etc&#46; have pointed out that sometimes &#8220;Rails isn&#8217;t good at that, take it out of Rails&#46;&#8221; Same thing for the database&#46; Split those things out into a different application&#46;</p> <p><strong>Bryan</strong>: Do your dry land work, know your toolchain, so that when the moment comes, you can dive in and find the problem&#46;</p> <p><em>We have a migration that takes a week to run because of text processing&#46; GC was running after every 10th DB statement&#46; Used Rails bench GC patch to overcome the issue with the migration&#46; Any issue running these?</em></p> <p><strong>Jason</strong>: We run those GC modifications and a few more in production, and they&#8217;re fine&#46;</p> <p><em>Most comversations revolve around items like database is slow, or Ruby is slow&#46; How can we use DTrace to streamline the process?</em></p> <p><strong>Jeremy</strong>: We spent 20 minutes over lunch (plus some preparation) to find a Memcache issue&#46; It&#8217;s worth it to spend a little time to learn the tool&#46;</p> <p><strong>Bryan</strong>: &#8220;Awk is God&#8217;s gift to all of us&#46;&#8221; When DTrace was being reviewed inside of Sun, folks commented &#8220;This reminds us of awk&#46;&#8221; &#8220;Thanks!&#8221;</p> <p><strong>Jason</strong>: We&#8217;re putting a tracing plugin in Rails as a remote process to collect data from a running app&#46; Apple has shown a commitment to get this in Leopard&#46; Textual and graphical output are possible&#46; I believe in DTrace a lot, and the tooling and documentation will go beyond its current state of an experts tool&#46;</p> <p><em>Lastly, what one closing thing would you like to say about Rails scalability?</em></p> <p><strong>Ian</strong>: Measure&#46;<br/> <strong>Jason</strong>: Don&#8217;t use relational databases&#46;<br/> <strong>Jeremy</strong>: I thought it was a Joyent sales pitch&#46;<br/> <strong>Bryan</strong>: Use DTrace (with Joyent accelerators of course)&#46;<br/></p> Nick Sieger urn:uuid:8396524a-7e00-4aad-8727-a5a0b3ec7ef3 2006-11-15T15:46:00+00:00 2010-11-22T18:06:58+00:00 RSpec Autotest now a Rails Plugin <p>Inspired by a <a href="http://rubyforge.org/pipermail/rspec-devel/2006-November/001219.html">posting on the RSpec list</a> and recent <a href="http://blog.nicksieger.com/articles/2006/09/13/auto-rspec#comment-143">comments stating that my Auto RSpec hack wasn&#8217;t working</a>, I&#8217;ve bitten the bullet and upgraded to <a href="http://rspec.rubyforge.org/upgrade.html">RSpec 0&#46;7&#46;2</a>, and made <code>rspec_autotest</code> <a href="http://svn.caldersphere.net/svn/main/plugins/rspec_autotest">a plugin</a> in the process&#46; So, herewith are the necessary incantations to auto&#45;rspec your project&#46; If you&#8217;ve tried my hack already, please remove any bits you previously had installed&#46;</p> <ul> <li>Install RSpec on Rails, following the <a href="http://rspec.rubyforge.org/documentation/rails/install.html">original instructions</a>&#46; As of RSpec 0&#46;7&#46;3, the specific version of ZenTest is no longer required&#46; Also, diff&#45;lcs is required to show unified diff output on <code>should ==</code> failures&#46;</li> </ul> <div class="typocode"><pre><code class="typocode_default ">gem install zentest -v 3.4.1 gem install diff-lcs gem install rspec script/plugin install svn://rubyforge.org/var/svn/rspec/tags/REL_0_7_2/vendor/rspec_on_rails/vendor/plugins/rspec</code></pre></div> <ul> <li>Install <code>rspec_autotest</code></li> </ul> <div class="typocode"><pre><code class="typocode_default ">script/plugin install http://svn.caldersphere.net/svn/main/plugins/rspec_autotest</code></pre></div> <ul> <li>Start autotest</li> </ul> <div class="typocode"><pre><code class="typocode_default ">rake spec:autotest</code></pre></div> <p>Please let me know if you experience any problems!</p> Nick Sieger urn:uuid:32ea8753-bf86-4fe8-bec2-4b2f432512fe 2009-04-11T04:10:51+00:00 2010-11-22T18:06:58+00:00 JRuby 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&#8217;s announcements</a> as much as anyone else&#46; <a href="http://olabini.com/blog/2009/04/jruby-on-rails-on-google-app-engine/">Ola keeps secrets well</a>&#46; He sent me a pull request for <a href="http://jruby-rack.kenai.com/pages/Home">jruby&#45;rack</a> just last week mentioning &#8220;some restrictive environments where you can&#8217;t start threads&#8221;&#46; I didn&#8217;t blink, and instead just merged his patch&#46;</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&#8217;t bad&#46; <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&#46; Even though Google&#8217;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&#45;in aspect didn&#8217;t bother me&#46; I&#8217;m a pragmatist first, and I believe that we as developers are the only ones locking ourselves to a platform&#46; We have a choice, after all&#46; 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&#46; The fact that their code is not useful on any other device isn&#8217;t stopping them&#46;</p> <p>The thing with AppEngine is that it&#8217;s a unique platform all unto itself&#46; That may seem brutally obvious, but the point seems to be lost in all the frenzy surrounding the Run&#45;Rails&#45;Struts&#45;Spring&#45;Groovy&#45;Grails&#45;Lift&#45;You&#45;Name&#45;It&#45;Framework on AppEngine this week&#46; I&#8217;m not saying it&#8217;s a bad idea to try to run Rails on AppEngine; quite the contrary&#46; I&#8217;m saying you need to be honest about the trade&#45;offs and constraints&#46; 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&#46; Google has a URL fetch library, and has hooked up Java&#8217;s <code>HttpURLConnection</code> to it, but none of the Ruby URL&#45;fetching libraries use it&#46;</li> <li>No ActiveRecord&#46; &#8216;Nuff said&#46; For some folks, that&#8217;s a welcome change, but wrapping your head around AppEngine&#8217;s BigTable&#45;backed data store takes some thought&#46; You just can&#8217;t view it like a SQL engine&#46;</li> <li>No RMagick/ImageScience/attachment_fu&#46; No <a href="/articles/2008/03/27/imagevoodoo-0-1-released">ImageVoodoo</a> even (no javax&#46;image APIs)&#46; Google has it&#8217;s own image manipulation API&#46;</li> <li>Startup/first request processing time is currently an issue&#46; It&#8217;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&#46; I can only assume Google has a plan to address this&#46;</li> <li>Crypto&#46; Although java&#46;security and javax&#46;crypto APIs are apparently <a href="http://code.google.com/appengine/docs/java/jrewhitelist.html">whitelisted</a>, I haven&#8217;t had time to figure out how to leverage them&#46; JRuby&#8217;s jruby&#45;openssl gem does not work, which means things like <code>digest</code> aren&#8217;t available&#46; That&#8217;s currently a blocker for Rails&#8217; cookie session store&#46;</li> <li>1000&#45;files limit per application&#46; 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&#46;</li> </ul> <p>These are just a sampling of some of the problems you&#8217;re dealing with on the AppEngine frontier&#46; They&#8217;re all solvable; it will take a little time and BST (blood, sweat and tears)&#46; The point is you can&#8217;t expect a Rails application on AppEngine to behave like all the Rails applications you&#8217;ve written previously&#46;</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&#46; You don&#8217;t have to worry about it&#46; Transparent scaling, monitoring, logging, everything below your application code is taken care of&#46; Single&#45;step deployment, with application versioning and rollback&#46; Scalable services: BigTable storage, memcached, scheduled tasks&#46; My friend <a href="http://googleappengine.blogspot.com/2009/02/best-buys-giftag-on-app-engine.html">Curt Thompson of Best Buy&#8217;s Giftag&#46;com</a> talks about how they leverage AppEngine for a non&#45;toy application&#46; (Curt also helped me get my <a href="http://nicksieger-notes.appspot.com/">Python AppEngine experiment</a> up and running&#46;)</p> <p>In the end, I&#8217;m still extremely excited about the prospect of using JRuby and Rails on AppEngine, and can&#8217;t wait to see what people build with these tools&#46; 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&#45;rack&#46;appspot&#46;com</a>&#46; The &#8220;application environment&#8221; 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&#46; The source code for the application is linked from the front page&#46; 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&#45;Rack 0&#46;9&#46;4</a>; Warbler is not yet using these components but you can build them yourself, drop them in and try them&#46; We&#8217;ll be updating JRuby, Warbler and other tools soon to make this process more seamless soon&#46; Stay tuned!</p> Nick Sieger urn:uuid:1e075610-8ab5-47a3-acae-7def4e3ab32a 2006-08-15T04:12:00+00:00 2010-11-22T18:06:59+00:00 Security Threat Last Week <p>What was the biggest security threat story for me last week? No, it was not the <a href="http://www.nytimes.com/2006/08/12/opinion/12sat1.html">disrupted liquid bomb plot</a>, it was the <a href="http://weblog.rubyonrails.com/2006/8/10/rails-1-1-6-backports-and-full-disclosure">Rails security hole</a> that caused quite a brouhaha among the Ruby community&#46; (Guess that shows my increasing tendency to lose touch with reality&#46; Maybe a sign of the miserable state of unrest in the world and how living in the land of the world&#8217;s only super&#45;power makes it easy to turn the other cheek? Or&#46;&#46;&#46;ok, ok&#46;&#46;&#46;it&#8217;s just me&#46;)</p> <p>From my view of the Rails security issue, there are actually quite a few interesting angles that came out of this story&#46;</p> <h2>Rails is Growing Up</h2> <p>This is the obvious one&#46; The first major fault to be discovered in Rails shows that Rails the codebase, Rails the core team, Rails the technology stack, and Rails the community is going through growing pains&#46; David was both praised and criticized widely for his handling of the disclosure&#46; Many rightly complained that the initial announcement didn&#8217;t give system maintainers enough information to decide whether the risk warranted disrupting normal operations to spend time to test and roll out the patch&#46; This was compounded by the fact that the initial announcement did not identify versions affected and instead assumed all past versions, which turned out not to be the case&#46;</p> <p>Others thanked the Rails team for their discretion and trusted the recommendation despite the fuzziness and lack of details&#46; These folks either were able to perform the upgrade much more easily or had some inkling of just how serious the issue was&#46;</p> <p>The aftermath showed that the Rails core quickly learned from the experience&#46; A <a href="http://lists.rubyonrails.org/mailman/listinfo/rails-security">security mailing list</a> and <a href="http://groups.google.com/group/rails-security">google group</a> were set up for future incidents and David promised to apply more <a href="http://weblog.rubyonrails.com/2006/8/10/rails-1-1-6-backports-and-full-disclosure">rigor and policy</a> to future announcements&#46;</p> <p>It seems pretty obvious that the size of the gaffe was such that to expose the details immediately would have had way too much potential to cause widespread data loss and denial of service&#46; In fact, the nature of the bug strikes me as one of those embarrassing bugs that every software developer commits at one point in their coding life where you amaze yourself at the short&#45;sightedness of your implementation&#46; I think the initial message could have been dispatched with information on the severity of the threat without necessarily disclosing the exact exploit&#46; So, essentially I agree with the approach that was taken, but the message left out details required to evaluate the threat&#46;</p> <h2>Threat Analysis</h2> <p>Two early <a href="http://blog.koehntopp.de/archives/1367-Ruby-On-Rails-Mandatory-Mystery-Patch.html">blog</a> <a href="http://blog.evanweaver.com/articles/2006/08/10/explanation-of-the-rails-security-vulnerability-in-1-1-4-others">posts</a> came out the day after claiming to know the details of the exploit&#46; It turned out that they didn&#8217;t quite understand what was afoot&#46; (Although Evan Weaver has since updated <a href="http://blog.evanweaver.com/articles/2006/08/10/explanation-of-the-rails-security-vulnerability-in-1-1-4-others">his post</a> to clarify his original analysis&#46;)</p> <p>The threat turned out to be a simple remote code execution issue&#46; The <code>:controller</code> dynamic expansion aspect of routing contained a bug that allowed arbitrary &#46;rb files in a Rails application to be executed undesirably&#46; By far the most dramatic consequence would be experienced if one&#8217;s <code>db/schema.rb</code> file were to be executed with a request for <code>/db/schema</code>, causing your entire database contents to be dropped and reloaded&#46;</p> <p>By examining the <a href="http://dev.rubyonrails.org/svn/rails/tags/rel_1-1-4/actionpack/lib/action_controller/routing.rb"><code>safe_load_paths</code></a> method defined in affected versions, it appears that the implementation tried to limit elements of the load path that matched the expanded <code>RAILS_ROOT</code> of the application&#46; Combine this with the fact that other elements of the routing system eagerly <code>require</code>&#8216;d files with inadequate bounds&#45;checking spells your recipe for disaster&#46;</p> <p>Many posters and commenters quipped that a simple <code>svn diff</code> was enough to give script kiddies or other black hats the information needed to exploit the issue&#46; Or was it? Given that the two early analyses turned out to be off the mark, were people in the know exercising more discretion by not disclosing more details? </p> <p>Personally, I spent more than an hour staring at the affected routing code trying to untangle the various metaprogramming tricks and regular expressions that make up the Rails routing system&#46; And I consider myself fairly adept at reading and understanding code! </p> <p>The truth of the matter is that, unless you&#8217;re a member of core or have a high level of familiarity and involvement with the Rails codebase, the svn diffs provide far too little context to decode the actual problem&#46;</p> <p>Does this speak to the obfuscated nature of the Rails codebase or to the relatively advanced nature of web programming in Ruby? If I had to pick one, it would be the latter, but I&#8217;m leaning towards neither&#46; The Rails codebase is not the most readable, comprehensible piece of code I&#8217;ve ever seen, but it does its job remarkably well&#46; Perhaps if the routing code in question was a bit more understandable by the masses, this rather obvious security issue wouldn&#8217;t have gone undetected for so long&#46;</p> <h2>Post&#45;1&#46;1&#46;6 Release Triage</h2> <p>A group of enthusiastic Railsers jumped onto #rails&#45;security on freenode shortly after the 1&#46;1&#46;6 release, where an effort had been organized to verify all the patches across various <a href="http://wiki.caboo.se/caboose/pages/1.1.6+Matrix">combinations of web servers and Rails versions</a>&#46; An IRC channel, a <a href="http://wiki.caboo.se/caboose/pages/1.1.6+Matrix">wiki</a>, Ruby, Zed&#8217;s <a href="http://rfuzz.rubyforge.org/design.html">RFuzz</a>, and a <a href="http://pastie.caboo.se/7993">piece of code</a> were all the tools required to get a distributed test verification process up and running&#46; This sort of thing happens all the time in the open source world, with programmers around the globe pitching in to raise the triage tent of the MASH unit&#46; Still, it was exciting to see and be a part of the action and to be reminded of the power of the collective whole working for a common cause&#46;</p> <h2>Dynamic Routing Harmful?</h2> <p>Rails&#8217;s dynamic routing code came under fire too, understandably so&#46; Maybe this is one case where the developer&#45;friendly approach of magically recognizing URLs goes a little too far? Production&#45;only routes that do away with the expandable path elements could easily be generated by visiting all the controllers in the codebase and generating a more static route for each &#45;&#45; sounds like a good idea for a plugin&#46; Perhaps the controller is the better place to store routing metadata anyway?</p> <div class="typocode"><pre><code class="typocode_ruby "><span class="keyword">class </span><span class="class">UsersController</span> <span class="punct">&lt;</span> <span class="constant">ActionController</span><span class="punct">::</span><span class="constant">Base</span> <span class="ident">map_default_route</span> <span class="comment"># could be optional</span> <span class="keyword">end</span> <span class="keyword">class </span><span class="class">PostsController</span> <span class="punct">&lt;</span> <span class="constant">ActionController</span><span class="punct">::</span><span class="constant">Base</span> <span class="ident">map_route_as_resource</span> <span class="keyword">end</span></code></pre></div> <p>Sounds like good fodder for future investigation!</p> Nick Sieger urn:uuid:9fe84534-3a40-40e8-8626-a15bb05d74b4 2007-03-16T16:55:00+00:00 2010-11-22T18:06:59+00:00 JRuby 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&#46;0 release of Rails Integration</a>, the bits that allow JRuby on Rails to be run out of a Java web archive (war)&#46; 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>&#46; Even though this is 1&#46;0, we&#8217;re still moving rapidly and would appreciate any and all feedback&#46; (And Robert is doing his best to keep up with changes in core&#46;)</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&#45;in collection of Rake tasks that bridge the inherent differences between Rails running on C Ruby vs&#46; JRuby&#46; We still have some work to do in some areas, such as database driver configuration, test database bootstrapping and launching unit tests&#46; 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&#45;specific case statement that&#8217;s in Rails&#8217; databases&#46;rake today</a>:</p> <div class="typocode"><pre><code class="typocode_ruby "><span class="ident">desc</span> <span class="punct">&quot;</span><span class="string">Recreate the test databases from the development structure</span><span class="punct">&quot;</span> <span class="ident">task</span> <span class="symbol">:clone_structure</span> <span class="punct">=&gt;</span> <span class="punct">[</span> <span class="punct">&quot;</span><span class="string">db:structure:dump</span><span class="punct">&quot;,</span> <span class="punct">&quot;</span><span class="string">db:test:purge</span><span class="punct">&quot;</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">[&quot;</span><span class="string">test</span><span class="punct">&quot;][&quot;</span><span class="string">adapter</span><span class="punct">&quot;]</span> <span class="keyword">when</span> <span class="punct">&quot;</span><span class="string">mysql</span><span class="punct">&quot;</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">(&quot;</span><span class="string">db/<span class="expr">#{RAILS_ENV}</span>_structure.sql</span><span class="punct">&quot;).</span><span class="ident">join</span><span class="punct">.</span><span class="ident">split</span><span class="punct">(&quot;</span><span class="string"> </span><span class="punct">&quot;).</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">&quot;</span><span class="string">postgresql</span><span class="punct">&quot;</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">[&quot;</span><span class="string">test</span><span class="punct">&quot;][&quot;</span><span class="string">host</span><span class="punct">&quot;]</span> <span class="keyword">if</span> <span class="ident">abcs</span><span class="punct">[&quot;</span><span class="string">test</span><span class="punct">&quot;][&quot;</span><span class="string">host</span><span class="punct">&quot;]</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">[&quot;</span><span class="string">test</span><span class="punct">&quot;][&quot;</span><span class="string">port</span><span class="punct">&quot;].</span><span class="ident">to_s</span> <span class="keyword">if</span> <span class="ident">abcs</span><span class="punct">[&quot;</span><span class="string">test</span><span class="punct">&quot;][&quot;</span><span class="string">port</span><span class="punct">&quot;]</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">[&quot;</span><span class="string">test</span><span class="punct">&quot;][&quot;</span><span class="string">password</span><span class="punct">&quot;].</span><span class="ident">to_s</span> <span class="keyword">if</span> <span class="ident">abcs</span><span class="punct">[&quot;</span><span class="string">test</span><span class="punct">&quot;][&quot;</span><span class="string">password</span><span class="punct">&quot;]</span> `<span class="ident">psql</span> <span class="punct">-</span><span class="constant">U</span> <span class="punct">&quot;</span><span class="string"><span class="expr">#{abcs[&quot;test&quot;][&quot;username&quot;]}</span></span><span class="punct">&quot;</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[&quot;test&quot;][&quot;database&quot;]}`</span> <span class="keyword">when</span> <span class="punct">&quot;</span><span class="string">sqlite</span><span class="punct">&quot;,</span> <span class="punct">&quot;</span><span class="string">sqlite3</span><span class="punct">&quot;</span> <span class="ident">dbfile</span> <span class="punct">=</span> <span class="ident">abcs</span><span class="punct">[&quot;</span><span class="string">test</span><span class="punct">&quot;][&quot;</span><span class="string">database</span><span class="punct">&quot;]</span> <span class="punct">||</span> <span class="ident">abcs</span><span class="punct">[&quot;</span><span class="string">test</span><span class="punct">&quot;][&quot;</span><span class="string">dbfile</span><span class="punct">&quot;]</span> `<span class="comment">#{abcs[&quot;test&quot;][&quot;adapter&quot;]} #{dbfile} &lt; db/#{RAILS_ENV}_structure.sql`</span> <span class="keyword">when</span> <span class="punct">&quot;</span><span class="string">sqlserver</span><span class="punct">&quot;</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[&quot;test&quot;][&quot;host&quot;]} -d #{abcs[&quot;test&quot;][&quot;database&quot;]} -i db\#{RAILS_ENV}_structure.sql`</span> <span class="keyword">when</span> <span class="punct">&quot;</span><span class="string">oci</span><span class="punct">&quot;,</span> <span class="punct">&quot;</span><span class="string">oracle</span><span class="punct">&quot;</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">(&quot;</span><span class="string">db/<span class="expr">#{RAILS_ENV}</span>_structure.sql</span><span class="punct">&quot;).</span><span class="ident">join</span><span class="punct">.</span><span class="ident">split</span><span class="punct">(&quot;</span><span class="string">; </span><span class="punct">&quot;).</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">&quot;</span><span class="string">firebird</span><span class="punct">&quot;</span> <span class="ident">set_firebird_env</span><span class="punct">(</span><span class="ident">abcs</span><span class="punct">[&quot;</span><span class="string">test</span><span class="punct">&quot;])</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">[&quot;</span><span class="string">test</span><span class="punct">&quot;])</span> <span class="ident">sh</span> <span class="punct">&quot;</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">&quot;</span> <span class="keyword">else</span> <span class="keyword">raise</span> <span class="punct">&quot;</span><span class="string">Task not supported by '<span class="expr">#{abcs[&quot;test&quot;][&quot;adapter&quot;]}</span>'</span><span class="punct">&quot;</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">&quot;</span><span class="string">Recreate the test databases from migrations</span><span class="punct">&quot;</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">(&quot;</span><span class="string">db/migrate/</span><span class="punct">&quot;)</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&#46; What would be most excellent is to eventually push some of these improvements back to the Rails core&#46;</p> Nick Sieger urn:uuid:091b1464-16fe-49ee-9d4b-ce18ddf2da0d 2006-05-15T03:12:00+00:00 2010-11-22T18:06:59+00:00 JRuby 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&#46; The Rails experience may soon be visiting a Java application server near you! Even though JRuby will be in perpetual catch&#45;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>&#46; Maybe Rails will never be mainstream, but the possibilities just got a whole lot more interesting&#46; I agree with <a href="http://jroller.com/page/obie?entry=jruby_on_rails_is_born">Obie</a> that this could be a game&#45;changer&#46;</p> <p>Now, a few comments about the ActiveRecord JDBC adapter&#46; This code can still be considered alpha quality at best&#46; It&#8217;s awesome that Tom and Charlie will be able to demo a top&#45;to&#45;bottom, working Rails app on JRuby, but don&#8217;t jump to conclusions yet that this will be anything like a write&#45;once, deploy&#45;to&#45;any&#45;database kind of experience&#46; But you didn&#8217;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>&#46; At the moment, I&#8217;ve only tried it with MySQL&#46; Most of the problems with it come from the lossy mapping from ActiveRecord&#8217;s abstraction of the database to JDBC&#8217;s&#46; (Although I suspect as more JDBC drivers are tried that there will eventually be compatibility issues with different implementations of the JDBC spec&#46;)</p> <p>Probably the thorniest issue is the one of type conversion&#46; ActiveRecord has a fairly simple notion of types: <code>:string, :text, :integer, :float, :datetime</code> etc&#46; Compare this to <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/sql/Types.html">JDBC&#8217;s</a>&#46; 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&#46; This will certainly need improvement to become a more robust solution&#46;</p> <p>Probably the most promising approach may be to create a patch that refactors much of the AR adapters&#8217; type conversion methods into separate modules that could be included into instances of the JDBC adapter depending on the underlying database&#46; Then the JDBC types wouldn&#8217;t be needed at all &#45;&#45; the existing AR database metadata could be reused&#46; Presumably this would require some petitioning of the Rails core team to accept the changes even though the changes don&#8217;t buy AR itself any additional flexibility&#46;</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 Sieger urn:uuid:a88e00d4-56b6-4b75-95e9-4e21e6b0387a 2007-09-04T02:48:40+00:00 2010-11-22T18:06:59+00:00 Warbler, 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&#46;0&#46;1</a> and <a href="http://rubyforge.org/frs/shownotes.php?release_id=14048">Goldspike 1&#46;3</a> releases into our environment, when my frustration hit a fever pitch&#46;</p> <p>See, I had always thought that the &#46;war packaging side of Goldspike was a little clunky and un&#45;ruby&#45;like, but I didn&#8217;t see a clear path to fixing it&#46; I had heard little complaints about it here and there: the little configuration DSL didn&#8217;t give you enough control or wasn&#8217;t documented well enough; the fact that it downloads libraries from the internet during assembly (convenient, but not safe or reproducible for production deployments)&#46;</p> <p>Also, in my own opinion it took the wrong approach to packaging Rails in a &#46;war file&#46; It puts the Rails application directory structure into the root of the &#46;war file where any web server or Java application server might mistakenly serve up your code as static content&#46; The Java &#46;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, &#46;svn directories and everything&#46; So I set out to fix this once and for all&#46;</p> <p>And so I present <a href="http://caldersphere.rubyforge.org/warbler/">Warbler</a>&#46; A little bird who chirpily steps up to the task of assembling your Rails application into a Java Web Archive (&#46;war)&#46; 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 &#46;war file, including your application and recent versions of JRuby and Goldspike, that&#8217;s deployable to your <a href="https://glassfish.dev.java.net/">favorite Java application server</a>&#46;</p> <p>There are a number of points about Warbler worth mentioning&#46;</p> <h3>Does one thing, well</h3> <p>Warbler only packages, and doesn&#8217;t care about anything else, like how to dispatch servlet requests to Rails&#46; This will allow for more runtime servlet binding mechanisms to take advantage of Warbler in the future&#46;</p> <h3>Fast and lightweight</h3> <p>50% less code than the Goldspike packaging plugin, yet does the job quickly and efficiently&#46;</p> <h3>Sane defaults</h3> <p>Warbler only packages code that you need to run the application, omitting database migrations and tests&#46; If your application is self&#45;sufficient (no external dependencies), then the out&#45;of&#45;the&#45;box configuration will probably work for you&#46; Public HTML/images/javascript/stylesheets go in the root of the webapp, where Java webservers expect them to be&#46;</p> <h3>Documented, flexible configuration</h3> <p>Need to customize your configuration? Run <code>warble config</code> and edit <code>config/warble.rb</code>&#46; All the options are there, commented and documented&#46;</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 &#46;jar files in the <code>vendor/plugins/warbler-0.9/lib</code> directory&#46; Warbler then makes his nest in your project&#8217;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 &#46;war file produced when running in plugin mode, since you won&#8217;t need him at runtime&#46; It&#8217;s the little details that matter&#46;</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>