Skip to main content

Rails Conf 2009 - Day 1 Trip Report

Posted by arungupta on May 4, 2009 at 11:43 PM PDT



Rails Conf 2009 started this morning. The first day consists of morning
and afternoon href="http://en.oreilly.com/rails2009/public/schedule/stype/154">tutorials.



I attended Nick Sieger's href="http://en.oreilly.com/rails2009/public/schedule/detail/7787">JRuby
on Rails tutorial, the slides are href="http://blog.nicksieger.com/jruby-railsconf-2009.pdf">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 href="http://en.oreilly.com/rails2009/public/schedule/detail/7590">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 href="http://rack.rubyforge.org/">Rack. A basic
Rack application can be "config.ru" or "app.rb", lets start with
"config.ru" Hello World:


style="text-align: left; background-color: rgb(204, 204, 255); width: 100%;"
cellpadding="2" cellspacing="2">
run
lambda { |env|

  [

    200,

    {

    'Content-Length' => '2',

    'Content-Type' => 'text/html',

    },

    ["hi"]

  ]

}



Run it as ...


style="text-align: left; background-color: rgb(204, 204, 255); width: 100%;"
cellpadding="2" cellspacing="2">
~/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" ..


style="text-align: left; background-color: rgb(204, 204, 255); width: 100%;"
cellpadding="2" cellspacing="2">
App
= lambda { |env|

  [

    200,

    {

    'Content-Length' => '2',

    'Content-Type' => 'text/html',

    },

    ["hi"]

  ]

}



And run it as ...


style="text-align: left; background-color: rgb(204, 204, 255); width: 100%;"
cellpadding="2" cellspacing="2">
~/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 ...


style="text-align: left; background-color: rgb(204, 204, 255); width: 100%;"
cellpadding="2" cellspacing="2">
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:



alt=""
src="http://blogs.sun.com/arungupta/resource/confs/sinatra-railsconf-tutorial-body-env-output.png">



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:


style="text-align: left; background-color: rgb(204, 204, 255); width: 100%;"
cellpadding="2" cellspacing="2">
~/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:


style="text-align: left; background-color: rgb(204, 204, 255); width: 100%;"
cellpadding="2" cellspacing="2">
~/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:


style="text-align: left; background-color: rgb(204, 204, 255); width: 100%;"
cellpadding="2" cellspacing="2">
class
BasicRack

     def call(env)

      body = if env["PATH_INFO"] ==
"/foo"

        "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 href="http://railscasts.com/episodes/151-rack-middleware">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:


style="text-align: left; background-color: rgb(204, 204, 255); width: 100%;"
cellpadding="2" cellspacing="2">
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

    def initialize(app)

        @app = app

    end

   

    def call(env)

       
@app.call(env)

    end

end



use MyMiddleware



run BasicRackApp.new



@app.call calls the next middleware in the chain.



Rack comes with couple of standard middleware, e.g.:


style="text-align: left; background-color: rgb(204, 204, 255); width: 100%;"
cellpadding="2" cellspacing="2">
use
Rack::CommonLogger



Example of an after filter:


style="text-align: left; background-color: rgb(204, 204, 255); width: 100%;"
cellpadding="2" cellspacing="2">
   
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:


style="text-align: left; background-color: rgb(204, 204, 255); width: 100%;"
cellpadding="2" cellspacing="2">
require
'sinatra'



is the simplest Sinatra application. Save it in a file
"basic-sinatra.rb" and run it as:


style="text-align: left; background-color: rgb(204, 204, 255); width: 100%;"
cellpadding="2" cellspacing="2">
~/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 href="http://blog.arungupta.me/2009/04/27/totd-79-getting-started-with-sinatra-applications-on-jruby-and-glassfish-gem.aspx">TOTD
#79. Add a simple GET method and "not_found" handler as:


style="text-align: left; background-color: rgb(204, 204, 255); width: 100%;"
cellpadding="2" cellspacing="2">
require
'rubygems'

require 'sinatra'



not_found do

  'hi from other'

end



get '/foo' do

    'hi from foo'

end



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 ...


style="text-align: left; background-color: rgb(204, 204, 255); width: 100%;"
cellpadding="2" cellspacing="2">
require
'rubygems'

require 'sinatra'



get '/env' do

    env.inspect

end



And it shows Rack environment hash at 'http://localhost:4567".



Another one ...


style="text-align: left; background-color: rgb(204, 204, 255); width: 100%;"
cellpadding="2" cellspacing="2">
require
'rubygems'

require 'sinatra'



get '/' do

end



post '/' do

end 



put '/' do

end



delete '/' do

end



This adds 4 HTTP methods with different routes.



No explicit render method, e.g.


style="text-align: left; background-color: rgb(204, 204, 255); width: 100%;"
cellpadding="2" cellspacing="2">
require
'rubygems'

require 'sinatra'



get '/' do

  content_type "application/json"

  { "foo" => "goo" }.to_json

end



No ".rhtml.erb" or ".json.erb", instead it's just ".erb". Add
"views/index.erb" as:


style="text-align: left; background-color: rgb(204, 204, 255); width: 100%;"
cellpadding="2" cellspacing="2">
<html>

  <body>

  Hello form Sinatra + ERB

  </body>

  </html>



And change GET method to:


style="text-align: left; background-color: rgb(204, 204, 255); width: 100%;"
cellpadding="2" cellspacing="2">
require
'rubygems'

require 'sinatra'



get '/' do

  erb :index

end



And the application now uses ERB templating.



Using HAML
templates
is simple, change to:


style="text-align: left; background-color: rgb(204, 204, 255); width: 100%;"
cellpadding="2" cellspacing="2">
require
'rubygems'

require 'sinatra'

require 'haml'



get '/' do

  haml :index

end



And add "views/index.haml" as:


style="text-align: left; background-color: rgb(204, 204, 255); width: 100%;"
cellpadding="2" cellspacing="2">
%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:


style="text-align: left; background-color: rgb(204, 204, 255); width: 100%;"
cellpadding="2" cellspacing="2">
require
'rubygems'

require 'sinatra'

require 'haml'



get '/' do

  erb :index

end



use_in_file_templates!



__END__



@@ index



<html>

  <body>

  Hello form Sinatra + ERB in file

  </body>

  </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:


style="text-align: left; background-color: rgb(204, 204, 255); width: 100%;"
cellpadding="2" cellspacing="2">
require
'rubygems'

require 'sinatra'

require 'haml'



get '/' do

  erb :index

end



get '/foo' do

  erb :foo

end



use_in_file_templates!



__END__



@@ index



<html>

  <body>

  Hello form Sinatra + ERB in file

  </body>

  </html>

 

@@ foo

<h1>FOO!</h1>



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:


style="text-align: left; background-color: rgb(204, 204, 255); width: 100%;"
cellpadding="2" cellspacing="2">
require
'rubygems'

require 'sinatra'

require 'haml'



helpers do

 

end



without defining on Main. Or ...


style="text-align: left; background-color: rgb(204, 204, 255); width: 100%;"
cellpadding="2" cellspacing="2">
require
'rubygems'

require 'sinatra'

require 'haml'



module helpers

    def self.dosomething(arg)

    end

end



get '/' do

    Helpers.dosomething

end



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 href="http://www.sinatrarb.com/">sinatrarb.com.



Check out the pictures from Day 1:


cellspacing="5">
style="width: 216px; height: 288px;" alt=""
src="http://lh6.ggpht.com/_wIoV5EX5M-0/Sf_L_IKKO0I/AAAAAAAAQpA/GXXYF1gY9Ys/s288/IMG_4975.JPG">
style="width: 216px; height: 288px;" alt=""
src="http://lh3.ggpht.com/_wIoV5EX5M-0/Sf_MA0tIRfI/AAAAAAAAQpY/306B2Y2F2ZE/s288/IMG_4978.JPG">
style="width: 288px; height: 216px;" alt=""
src="http://lh4.ggpht.com/_wIoV5EX5M-0/Sf_MCyGl1gI/AAAAAAAAQpw/rsAqQP6Zstk/s288/IMG_4982.JPG">
style="width: 288px; height: 216px;" alt=""
src="http://lh5.ggpht.com/_wIoV5EX5M-0/Sf_MEapc_gI/AAAAAAAAQqA/2XLm-i_KJYM/s288/IMG_4984.JPG">
style="width: 288px; height: 216px;" alt=""
src="http://lh3.ggpht.com/_wIoV5EX5M-0/Sf_MGiWVOPI/AAAAAAAAQqk/a1mtcQ7MA6g/s288/IMG_4988.JPG">
style="width: 288px; height: 216px;" alt=""
src="http://lh5.ggpht.com/_wIoV5EX5M-0/Sf_MIoFPxMI/AAAAAAAAQq8/2sjex5LWqUM/s288/IMG_4991.JPG">
style="width: 288px; height: 216px;" alt=""
src="http://lh4.ggpht.com/_wIoV5EX5M-0/Sf_MJ3WZqBI/AAAAAAAAQrM/fEH-YUN2sQo/s288/IMG_4993.JPG">
style="width: 288px; height: 216px;" alt=""
src="http://lh5.ggpht.com/_wIoV5EX5M-0/Sf_MNBttmLI/AAAAAAAAQr0/dnaw0LzCljQ/s288/IMG_4998.JPG">
style="width: 288px; height: 216px;" alt=""
src="http://lh6.ggpht.com/_wIoV5EX5M-0/Sf_MPNFKIaI/AAAAAAAAQsU/NGk-5he4KZc/s288/IMG_5002.JPG">
style="width: 288px; height: 216px;" alt=""
src="http://lh3.ggpht.com/_wIoV5EX5M-0/Sf_MQ3as1AI/AAAAAAAAQss/zNYzaRrlZUM/s288/IMG_5006.JPG">
style="width: 288px; height: 216px;" alt=""
src="http://lh4.ggpht.com/_wIoV5EX5M-0/Sf_MVKOQA2I/AAAAAAAAQtk/ctYQPDa4dfk/s288/IMG_5013.JPG">
style="width: 288px; height: 216px;" alt=""
src="http://lh5.ggpht.com/_wIoV5EX5M-0/Sf_MVzUmjdI/AAAAAAAAQts/eiNdlMUKKm8/s288/IMG_5014.JPG">



The evening concluded with dinner at href="http://www.mandalaybay.com/dining/burgerbar.aspx">Burger
Bar at Mandalay Bay along with Project
Kenai
team.



And check the evolving album at:



src="http://picasaweb.google.com/s/c/bin/slideshow.swf"
flashvars="host=picasaweb.google.com&RGB=0x000000&feed=http%3A%2F%2Fpicasaweb.google.com%2Fdata%2Ffeed%2Fapi%2Fuser%2Farun.gupta%2Falbumid%2F5332204752672779393%3Fkind%3Dphoto%26alt%3Drss"
pluginspage="http://www.macromedia.com/go/getflashplayer"
height="192" width="288">




On to href="http://blog.arungupta.me/2009/04/27/glassfish-and-netbeans-at-rails-conf-2009.aspx">GlassFish
talk tomorrow, and running with href="http://twitter.com/railsConfRunner">@railsConfRunner
in the morning before that :)



Technorati: conf
railsconf
lasvegas
jruby
rubyonrails
sinatra
glassfish

Related Topics >>