Rails Conf 2009 started this morning. The first day consists of morning and afternoon tutorials.
I attended Nick Sieger’s JRuby on Rails tutorial, the slides are available. A survey in the room showed:
- 95% comfortable with Ruby/Rails
- 80% have used JRuby
- 10% use JRuby actively
Here are some of the key points highlighted in the tutorial:
Why JRuby ?
- JRuby is “Less Bitter Java”, after all Java is a great platform.
- Concurrency (Native threading)
- Reliability (well-behaved because of Hotspot compiler, no process monitoring, etc)
- Encapsulation (take a Rails application, bundle it as a single deployable artifact that is fully contained)
- Choice (Any Java application server, huge breadth of Java libraries, and can write thin Ruby wrappers around Java libraries)
Download JDK 5 minimum, JDK 6 preferred, MySQL 5.x, JRuby 1.2 (1.3.0 RC1 OK too), GlassFish v2.1 b60e
Common options
- –server: Run with server VM, better performance
- –headless: No UI
- –properties: Show tweaks for compiler, JIT compiling, thread pooling etc
- -J<java-opt>: Pass any Java properties
- -J-Xmx1G: Increase memory to 1G
Drawbacks: No fork(), No native extensions (for example ParseTree, EventMachine, RMagic cannot be used), No tty for subprocesses, Startup time slow for short scripts
Advantages: Improved versions of some Ruby APIs (tempfile, mutex, thread, timeout), 1.8 and 1.9 in a single install (jruby –1.9), Wrap Java libraries and APIs in Ruby
The slides have much more details in terms of deployment options (WAR-based, GlassFish Gem), and many other interesting details Scroll to slide #68 to understand all the guts of kenai.com – a real life application running using JRuby, Rails, and GlassFish.
The afternoon tutorial for me was A Hat Full of Tricks with Sinatra. The tutorial was completely code driven with no slides, just love that format!
The tutorial started with a brief introduction to Rack. A basic Rack application can be “config.ru” or “app.rb”, lets start with “config.ru” Hello World:
| run lambda { |env| [ 200, { 'Content-Length' => '2', 'Content-Type' => 'text/html', }, ["hi"] ] } |
Run it as …
| ~/samples/railsconf/sinatra/basic-rack >~/tools/jruby/bin/jruby -S rackup [2009-05-04 13:40:18] INFO WEBrick 1.3.1 [2009-05-04 13:40:18] INFO ruby 1.8.6 (2009-03-16) [java] [2009-05-04 13:40:18] INFO WEBrick::HTTPServer#start: pid=90964 port=9292 127.0.0.1 – - [04/May/2009 13:40:27] “GET / HTTP/1.1″ 200 2 0.0160 127.0.0.1 – - [04/May/2009 13:40:27] “GET /favicon.ico HTTP/1.1″ 200 2 0.0060 127.0.0.1 – - [04/May/2009 13:40:30] “GET /favicon.ico HTTP/1.1″ 200 2 0.0100 |
“config.ru” is the default Rackup script, otherwise need to specify the name. And now “app.rb” ..
| App = lambda { |env| [ 200, { 'Content-Length' => '2', 'Content-Type' => 'text/html', }, ["hi"] ] } |
And run it as …
| ~/samples/railsconf/sinatra/basic-rack >~/tools/jruby/bin/jruby -S rackup app.rb [2009-05-04 13:43:57] INFO WEBrick 1.3.1 [2009-05-04 13:43:57] INFO ruby 1.8.6 (2009-03-16) [java] [2009-05-04 13:43:57] INFO WEBrick::HTTPServer#start: pid=90990 port=9292 127.0.0.1 – - [04/May/2009 13:44:09] “GET / HTTP/1.1″ 200 2 0.0110 |
In both cases, the application is accessible at “http://localhost:9292″.
Change the basic “config.ru” to convert into a class as …
| class BasicRack def call(env) body = “Hello from a class” [ 200, { 'Content-Length' => body.size.to_s, 'Content-Type' => 'text/html', }, [body] ] end end run BasicRack.new |
and run the same way as earlier.
Change body to “env.inspect” to see an output as:

Sinatra allows reloading of application but that “feature” will be removed soon. Instead install shotgun (which does not work with JRuby yet!). Anyway, install the gem:
| ~/samples/railsconf/sinatra/basic-rack >~/tools/jruby/bin/jruby -S gem install shotgun JRuby limited openssl loaded. gem install jruby-openssl for full support. http://wiki.jruby.org/wiki/JRuby_Builtin_OpenSSL Successfully installed configuration-0.0.5 Successfully installed launchy-0.3.3 Successfully installed shotgun-0.2 3 gems installed Installing ri documentation for launchy-0.3.3… Installing RDoc documentation for launchy-0.3.3… |
And run as:
| ~/samples/railsconf/sinatra/basic-rack >~/tools/jruby/bin/jruby -J-Djruby.fork.enabled=true -S shotgun [2009-05-04 13:55:46] INFO WEBrick 1.3.1 [2009-05-04 13:55:46] INFO ruby 1.8.6 (2009-03-16) [java] == Shotgun starting Rack::Handler::WEBrick on localhost:9393 [2009-05-04 13:55:46] INFO WEBrick::HTTPServer#start: pid=91089 port=9393 |
Process separate bodies depending upon the info:
| class BasicRack def call(env) body = if env["PATH_INFO"] == “/foo”< br> “in foo” else “in other” end [ 200, { 'Content-Length' => body.size.to_s, 'Content-Type' => 'text/html', }, [body] ] end end run BasicRack.new |
Accessing “http://localhost:9292/foo” shows “in foo” and accessing “http://localhost:9393″ shows “in other”.
Target application is the last application specified by “run”.
Rack supports middleware which are like filters, they can applied before/after a message is processed.
Rack will initialize middleware at load, so hold on to that application as shown:
| class BasicRackApp def call(env) body = “hello from app” [ 200, { 'Content-Length' => body.size.to_s, 'Content-Type' => 'text/html', }, [body] ] end end class MyMiddleware use MyMiddleware run BasicRackApp.new |
@app.call calls the next middleware in the chain.
Rack comes with couple of standard middleware, e.g.:
| use Rack::CommonLogger |
Example of an after filter:
| def call(env) status, headers, body = @app.call(env) body.map! { |part| part.upcase} [status, headers, body] end |
Lots of other filters available.
With a basic Rack understanding, lets build a Sinatra app:
| require ‘sinatra’ |
is the simplest Sinatra application. Save it in a file “basic-sinatra.rb” and run it as:
| ~/samples/railsconf/sinatra/basic-sinatra >~/tools/jruby/bin/jruby -rubygems basic-sinatra.rb == Sinatra/0.9.1.1 has taken the stage on 4567 for development with backup from WEBrick [2009-05-04 14:40:14] INFO WEBrick 1.3.1 [2009-05-04 14:40:14] INFO ruby 1.8.6 (2009-03-16) [java] [2009-05-04 14:40:14] INFO WEBrick::HTTPServer#start: pid=91396 port=4567 |
The application is now available at “http://localhost:4567″. BTW, this app can easily be run using GlassFish Gem as explained in TOTD #79. Add a simple GET method and “not_found” handler as:
| require ‘rubygems’ require ‘sinatra’ not_found do get ‘/foo’ do |
Every time a request comes in, it builds a request context, instance evals lambda and finds the one that hits.
Sinatra takes care of status and headers, the application needs to process the body.
Another one …
| require ‘rubygems’ require ‘sinatra’ get ‘/env’ do |
And it shows Rack environment hash at ‘http://localhost:4567″.
Another one …
| require ‘rubygems’ require ‘sinatra’ get ‘/’ do post ‘/’ do put ‘/’ do delete ‘/’ do |
This adds 4 HTTP methods with different routes.
No explicit render method, e.g.
| require ‘rubygems’ require ‘sinatra’ get ‘/’ do |
No “.rhtml.erb” or “.json.erb”, instead it’s just “.erb”. Add “views/index.erb” as:
| <html> <body> Hello form Sinatra + ERB </body> </html> |
And change GET method to:
| require ‘rubygems’ require ‘sinatra’ get ‘/’ do |
And the application now uses ERB templating.
Using HAML templates is simple, change to:
| require ‘rubygems’ require ‘sinatra’ require ‘haml’ get ‘/’ do |
And add “views/index.haml” as:
| %html %body %h1 Hello from HAML |
And now the application is using HAML templates.
__END__ is the end of Ruby, can be anything after that and it’ll not barf. Sinatra uses it for in file templates:
| require ‘rubygems’ require ‘sinatra’ require ‘haml’ get ‘/’ do use_in_file_templates! __END__ @@ index <html> |
Start with in-file templates, and then move out to separate directory (“views”) once grows big. But no syntax highlighting etc.
Add your custom template as:
| require ‘rubygems’ require ‘sinatra’ require ‘haml’ get ‘/’ do get ‘/foo’ do use_in_file_templates! __END__ @@ index <html> |
With this file “http://localhost:4567/” uses ERB template, and “http://localhost:4567/foo” uses “foo” template.
Sinatra defines on Main. The before filters work before every single request, executed in the same context as lambda. Can be used if every request needs to do some setup.
Helpers can be defined as:
| require ‘rubygems’ require ‘sinatra’ require ‘haml’ helpers do |
without defining on Main. Or …
| require ‘rubygems’ require ‘sinatra’ require ‘haml’ module helpers get ‘/’ do |
Don’t define something on Main, it’s a bad practice.
Extension is a nice package that can be shared for other Sinatra developers to use, like Rails plugins but does not have boilerplate, much easier to do.
Rest of tutorial was quite fast paced so the code samples could not be captured. But there is boatload of information available at sinatrarb.com.
Check out the pictures from Day 1:
The evening concluded with dinner at Burger Bar at Mandalay Bay along with Project Kenai team.
And check the evolving album at:
On to GlassFish talk tomorrow, and running with @railsConfRunner in the morning before that
Technorati: conf railsconf lasvegas jruby rubyonrails sinatra glassfish
Related posts:
[Trackback] Slides of the presentations can be found here as they are released Follow "official" news on Twitter. DHH Keynote notes. Video links to come soon. Some good notes from day1. Please tweet links to @danielwanja for any good blog articles that does live c…
Comment by OnRails.org — May 5, 2009 @ 11:15 am