Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Web Development with Sinatra

562a1c3432e73f12cb5527f315b7ed2f?s=47 Bob Nadler
December 10, 2012

Web Development with Sinatra

Fundamentals and some "advanced" topics for writing web applications using Ruby's Sinatra library.

562a1c3432e73f12cb5527f315b7ed2f?s=128

Bob Nadler

December 10, 2012
Tweet

Transcript

  1. Web Development with Sinatra

  2. What is Sinatra?

  3. “Sinatra is a DSL for quickly creating web applications in

    Ruby with minimal effort.” - sinatrarb.com/intro
  4. It’s a LIBRARY not a FRAMEWORK.

  5. huh?

  6. http://stackoverflow.com/questions/148747/what-is-the-difference-between-a-framework-and-a-library

  7. http://www.quora.com/Software-Engineering/Whats-the-difference-between-a-library-and-a-framework

  8. “A library is essentially a set of functions that you

    can call... Each call does some work and returns control to the client.” “A framework embodies some abstract design, with more behavior built in... you need to insert your behavior into various places in the framework.” http://martinfowler.com/bliki/InversionOfControl.html Martin Fowler
  9. Sinatra allows you to structure your application to fit the

    problem you’re trying to solve instead of the other way around.
  10. Simplest Example require 'sinatra' get '/hi' do "Hello World!" end

    $ gem install sinatra $ ruby hi.rb == Sinatra has taken the stage .. >> Listening on 0.0.0.0:4567
  11. Road Map • Fundamentals • “Advanced” Topics • Use Cases

  12. Fundamentals Anatomy of a Route Handler HTTP Verb get post

    put delete patch URL Behavior get '/hello/:name' do "Hello, #{params[:name]}" end Parameters
  13. Fundamentals The First Sufficient Match Wins get '/*' do "NOM

    NOM NOM" end get '/specific' do "I'll never be matched... you'll won't see me!" end
  14. Fundamentals Halting a Request get '/halt' do "You will not

    see this output." halt 500 end
  15. Fundamentals Redirecting a Request get '/search' do redirect 'http://www.google.com', 301

    end Optional
  16. Fundamentals Views: Inline Templates require 'sinatra' get '/index' do erb

    :index end __END__ @@index <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Inline Template</title> </head <body> <h1>It Worked!</h1> </body> </html> ERB by default, but any templates supported by Tilt will work Each inline template must have a unique name
  17. Fundamentals Views: External Templates Just place your templates in a

    /views folder and Sinatra will pick them up; you’re route handlers stay the same
  18. Fundamentals Views: Passing Data get '/home' do @name = 'John

    Doe' erb :home end __END__ @@home <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Inline Template</title> </head <body> <h1><%= @name %></h1> </body> </html>
  19. Fundamentals Filters before do content_type :json end after do "After

    filter called" end
  20. Fundamentals Helpers helpers do def link(name) case :name when :about

    then '/about' when :index then '/index' else "/page/#{name}" end end # in your view template <a href="<%= link :about %>">About</a> # -- OR -- # define helpers as methods in a module module MyHelpers # helper methods end helpers MyHelpers
  21. Fundamentals Configuration configure :development do set :db, Sequel.sqlite('db/development.sqlite') end configure

    :production do set :db, Sequel.connect(ENV['DATABASE_URL']) end
  22. Fundamentals Caching get '/cache' do expires 3600, :public, :must_revalidate "This

    page rendered at #{Time.now}." end See http://www.mnot.net/cache_docs/ for an explanation of HTTP caching options
  23. Fundamentals Sessions configure do enable :sessions end get '/set' do

    session[:foo] = Time.now "Session time was set." end get '/fetch' do "Session value: #{session[:foo]}" end get '/unset' do session.clear redirect '/fetch' end
  24. Fundamentals Attachments before do content_type :txt end get '/attachment' do

    attachment 'path/to/my-attachment.txt' end
  25. Fundamentals Testing with rack-test require 'my_sinatra_app' require 'test/unit' require 'rack/test'

    class MyAppTest < Test::Unit::TestCase include Rack::Test::Methods def app Sinatra::Application end def test_my_default get '/' assert_equal 'Hello World!', last_response.body end def test_with_params get '/meet', :name => 'Frank' assert_equal 'Hello Frank!', last_response.body end def test_with_rack_env get '/', {}, 'HTTP_USER_AGENT' => 'Songbird' assert_equal "You're using Songbird!", last_response.body end end
  26. Advanced Topics Modular vs. “Classic” “For some reason, it is

    a common misconception that modular applications are superior to classic applications, and that really advanced users only use modular style... This is utter nonsense and no one on the Sinatra core team shares this view. Sinatra is all about simplicity and if you can use a classic application, you should.” -- Sinatra Up and Running
  27. Advanced Topics Reasons to Use Modular you don’t want to

    pollute the Object namespace (writing a Gem) combining multiple Sinatra apps in a single process use Sinatra app as middleware
  28. Advanced Topics Simplest Modular Example require 'sinatra/base' class MyApp <

    Sinatra::Base get '/hi' do "Hello World!" end # Only start the server if the file # has been executed directly # # $0 is the executed file # __FILE__ is the current file run! if __FILE__ == $0 end
  29. Advanced Topics Running with Rack: Rackup File # In a

    file named my_app.rb require 'sinatra/base' class MyApp < Sinatra::Base get '/hi' do "Hello World!" end end # in a separate file named config.ru require './my_app' run MyApp # launch the server using # rackup command or shotgun
  30. Advanced Topics Running with Rack: Middleware Chain # In a

    file named my_app.rb require 'sinatra/base' class Foo < Sinatra::Base get('/foo') { 'foo' } end class Bar < Sinatra::Base get('/bar') { 'bar' } use Foo end # config.ru require 'my_app' run Bar # Or Foo and Bar can be in separate files # remember... it's just Ruby!
  31. Advanced Topics Running with Rack: Cascade require 'sinatra/base' class Foo

    < Sinatra::Base get('/foo') { 'foo' } end class Bar < Sinatra::Base get('/bar') { 'bar' } end # config.ru require 'my_app' run Rack::Cascade, [Foo, Bar] # Differences: # * _slightly_ better performance, but only if you have a lot of endpoints # * you can use any Rack app (like Rails)
  32. Advanced Topics Extensions: LinkedIn Example

  33. Use Cases Prototyping Web Apps API Server for iOS /

    Android / JavaScript Apps HTML5 Mobile Apps
  34. Resources • http://rubydoc.info/gems/sinatra/file/README.rdoc • http://www.sinatrarb.com/documentation • Sinatra: Up and Running

    (http://shop.oreilly.com/product/0636920019664.do) • http://stackoverflow.com/questions/148747/what-is-the-difference-between-a- framework-and-a-library • http://www.quora.com/Software-Engineering/Whats-the-difference-between-a- library-and-a-framework • http://martinfowler.com/bliki/InversionOfControl.html • http://www.mnot.net/cache_docs/ • https://github.com/bnadlerjr/sidestep • https://github.com/bnadlerjr/leaflet • https://github.com/bnadlerjr/sinatra-linkedin • https://github.com/bnadlerjr/fuelyo • http://rubygems.org/gems/middleman
  35. Questions? Bob Nadler @bnadlerjr bnadler@cyrusinnovation.com