• Save
Swing when you're winning - an introduction to Ruby and Sinatra
Upcoming SlideShare
Loading in...5
×
 

Swing when you're winning - an introduction to Ruby and Sinatra

on

  • 4,866 views

Session originally given at Scotch on the Rocks 2013 in Edinburgh. ...

Session originally given at Scotch on the Rocks 2013 in Edinburgh.

In this session we will explore how to build a RESTful-based application using the Sinatra framework, built on top of the Ruby programming language. We will explore installing Ruby, creating our first Sinatra application, the use of route definitions to handle multiple METHOD request types, including GET and POST requests, data persistence in a SQLite database, and how to return data in multiple formats including JSON and HTML. The RESTful approach and ease of use offered by Sinatra make it a great choice for underlying API requests which you can implement and call from any programming language of your choice.

Statistics

Views

Total Views
4,866
Views on SlideShare
4,853
Embed Views
13

Actions

Likes
2
Downloads
0
Comments
0

1 Embed 13

http://lanyrd.com 13

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Swing when you're winning - an introduction to Ruby and Sinatra Swing when you're winning - an introduction to Ruby and Sinatra Presentation Transcript

  • == Sinatra has taken to the stage with backup fromMatt Gifford@coldfumonkehwww.monkehworks.com
  • “SWING WHEN YOU’RE WINNING”AN INTRODUCTION TOSINATRA & RUBY
  • I build stuffand I write about building stuff too
  • WHAT WE’LL COVER:Getting your first Sinatra project up and runningWhat is Sinatra?Brief overview of a Sinatra application structureHandling routes and formatsDeploying to Heroku ** other options do exist
  • LIVE CODE DEMOS?WHAT COULD POSSIBLYGO WRONG?
  • NOT SURE IF I SHOULD BE HEREOR WATCHING SOMEONE ELSE
  • WHAT ELSE IS ON?Using personas in service design - continuouslyMura 6 for developersTuüli Aalto-NyyssonenSteve Withington
  • WAIT!You’re a ColdFusion developer, aren’t you?And this is a ColdFusion conference, isn’t it?
  • YES I AM!(and proud of it)
  • BACK TO SINATRA
  • WHY NOT RAILS?It is awesome though...Rails is quite large and sometimes too muchmonkeh$ rails create [stuff]Ships with ORM, routes, test suites etcEasily installed with RubyInstaller(.org)
  • SO WHY SINATRA?Doesn’t force any frameworkExtremely lightweightA Domain Specific Language (DSL)Incredibly quick and simple(but plays well with others if you want to)
  • SO WHY SINATRA?Runs on RackCan be a single file web applicationCan use a number of JavaScript librariesCan use a number of template enginesIt also means I can show pictures like this...
  • MORE BOUNCE TO THE OUNCE
  • DEVELOPMENT IS QUICK!
  • “simplicityistheultimatesophistication”Leonardo da Vinci
  • SINATRA IS GREAT FORREST APIsSmall appsuseful for AJAX calls to dataKeeping your simple application simpleIf it gets too big, consider using Rails (or CF)
  • HOW SIMPLE?
  • application.rbrequire rubygemsrequire sinatraget /hi do"Hello World!"endTHIS SIMPLE!
  • monkeh$ ruby application.rb== Sinatra/1.4.2 has taken to the stage on 4567 for development withbackup from Thin>> Thin web server (v1.5.1 codename Straight Razor)>> Maximum connections set to 1024>> Listening on localhost:4567, CTRL+C to stopRUNNING THE APP
  • IMPRESSIVE, RIGHT?
  • require rubygemsrequire sinatraget /hi do"Hello World!"endWHAT’S GOING ON?
  • require rubygemsrequire sinatraget /hi do"Hello World!"endWHAT’S GOING ON?<--- Ruby package manager
  • require rubygemsrequire sinatraget /hi do"Hello World!"endWHAT’S GOING ON?<--- Ruby package manager<--- Sinatra gem
  • require rubygemsrequire sinatraget /hi do"Hello World!"endWHAT’S GOING ON?<--- Ruby package manager<--- Sinatra gem<--- GET request
  • require rubygemsrequire sinatraget /hi do"Hello World!"endWHAT’S GOING ON?<--- Ruby package manager<--- Sinatra gem<--- GET request<--- response
  • require rubygemsrequire sinatraget /hi do"Hello World!"endNO RETURN?<--- the return is implied
  • get /hi do"Hello World!"endROUTE BLOCKS<--- this is a route blockA route block is an HTTP method paired witha URL-matching pattern.Processing takes place within the block (database calls etc)and the result is sent to the browser.
  • RESTUniform InterfaceClient-ServerCacheableHATEOASLayered SystemStatelessHypermedia as the Engineof Application State
  • SINATRA CAN DO THAT!CachingMultiple RoutesContent TypesAll HTTP verbs supportedGood times!
  • RESTget / do.. show something ..endpost / do.. create something ..endput / do.. replace something ..endpatch / do.. modify something ..enddelete / do.. annihilate something ..endoptions / do.. appease something ..endlink / do.. affiliate something ..endunlink / do.. separate something ..end
  • ROUTESget / do"Home page"endget /hello do"Hello!"endget /hello/:name do"Hello! #{params[:name]}"end
  • ROUTESget /say/*/to/* do# matches /say/hello/to/worldparams[:splat] # => ["hello", "world"]endget /download/*.* do# matches /download/path/to/file.xmlparams[:splat] # => ["hello", "world"]endget /download*.* do |path, ext|# matches /download/path/to/file.xml[path, ext] # => ["path/to/file", "xml"]end
  • ROUTESget %r{/hello/([w]+)} do"Hello, #{params[:captures].first}!"endget /posts.?:format? do# matches "/posts " and any extension# eg "GET /posts.xml" or "GET /posts.json"end
  • ROUTESget /hi, :agent => /Mozilla/(d.d)sw?/ do"You’re using Mozilla version #{params[:agent][0]}"endget /hi do# matches all non-Mozilla browsersend
  • GETTING STARTEDInstall RubyBathe in Ruby deliciousnessCreate your application fileInstall the Sinatra gem
  • http://rvm.io
  • monkeh$ rvm install 1.9.3monkeh$ rvm use --default 1.9.3monkeh$ rvm use jrubyhttp://cheat.errtheblog.com/s/rvm
  • GEMS?
  • GEMS?RubyGem distributes librariesapt-getSimilar in functionality to:A library is self-contained in a gemportageyum
  • GEMS!monkeh$ gem install [gem]monkeh$ gem uninstall [gem]monkeh$ gem listmonkeh$ gem fetch [gem]
  • BACK TO SINATRA
  • INSTALLINGmonkeh$ gem install sinatramonkeh$ gem install shotgun
  • DEMO TIME
  • DIRECTORY STRUCTURE| -- application.rb
  • SINGLE PAGE APPapplication.rbrequire rubygemsrequire sinatraget / dohtml = <form method="post">html += <input type="text" placeholder="Add the URL to shorten here..."html += name="url" id="url" />html += <input type="submit" value="Shorten!" />html += </form>htmlendpost / dohtml = <p>Thanks for submitting a URL.</p>htmlend
  • VIEWSMultiple template languages available, including:buildererbhamlsassliquidmarkdown
  • USING VIEWSapplication.rbrequire rubygemsrequire sinatraget / doerb :indexendpost / doerb :indexendviews/index.erb<form method="post"><input type="text" placeholder="Add the URL to shorten here..."name="url" id="url" /><input type="submit" value="Shorten!" /></form>
  • DIRECTORY STRUCTURE| -- application.rb| -- views-- index.erb
  • LAYOUTSA template that calls yield to draw in view dataCan also be managed through route blocksA template called “layout” will be used by default
  • USING LAYOUTSviews/layout.erb<!DOCTYPE html><html><head><title>Sinatra Intro</title></head><body><%= yield %></body></html>views/index.erb<form method="post"><input type="text" placeholder="Add the URL to shorten here..."name="url" id="url" /><input type="submit" value="Shorten!" /></form>
  • USING LAYOUTSviews/layout.erb<!DOCTYPE html><html><head><title>Sinatra Intro</title></head><body><%= yield %></body></html>views/index.erb<form method="post"><input type="text" placeholder="Add the URL to shorten here..."name="url" id="url" /><input type="submit" value="Shorten!" /></form>
  • DIRECTORY STRUCTURE| -- application.rb| -- views-- index.erb-- layout.erb
  • STATIC CONTENTAll static content is stored within a new directory“public”This is primarily forJavascriptCSSImages
  • DIRECTORY STRUCTURE| -- application.rb| -- views-- index.erb-- layout.erb| -- public-- css-- style.css-- javascript
  • STATIC CONTENT?
  • HELPERSapplication.rbhelpers dodef random_string(length)rand(36**length).to_s(36)enddef get_site_url(short_url)http:// + request.host + / + short_urlenddef generate_short_url(long_url@shortcode = random_string 5get_site_url(@shortcode)endend
  • FILTERSapplication.rb# This code will run before each event# Very useful for debugging parameters sent via the consolebefore doputs [Params]p paramsend# This code will run after each eventafter doputs response.statusend
  • CONFIGURATIONWill run once at startupCan be used toset application-wide values and optionsperform certain processes per environment
  • CONFIGURATIONconfigure do# All environmentsendconfigure :production do# Production onlyendconfigure :development, :test do# Development and Testend
  • CONFIGURATIONconfigure doset :variable, foo# multiple optionsset :variable1 => Hello, :variable2 => world# same as set :option, trueenable :option# same as set :option, falsedisable :optionendget / dosettings.variable? # => truesettings.variable # => fooend
  • CONFIGURATIONconfigure :development do# very useful for debugging parameters sent via the consolebefore doputs [Params]p paramsendend
  • DATAMAPPERSame API can talk to multiple datastoresUses adapters to achieve thissqlitemysqlpostgresql
  • DATAMAPPERDefine mappings in your modelComes bundled with tools to assist withmigrationconstraintstransactionstimestampsvalidations...and more!
  • INCLUDE THE LIBRARYapplication.rbrequire rubygemsrequire sinatrarequire data_mapper <--- DataMapper gem
  • CONFIGURATIONapplication.rbconfigure do# load models$LOAD_PATH.unshift("#{File.dirname(__FILE__)}/lib")Dir.glob("#{File.dirname(__FILE__)}/lib/*.rb") { |lib|require File.basename(lib, .*)}DataMapper::setup(:default, "sqlite3://#{Dir.pwd}/myDatabase.db")DataMapper.finalizeDataMapper.auto_upgrade!end
  • MODELlib/short_url.rbclass ShortURLinclude DataMapper::Resourceproperty :short_url, String, key: true, unique_index: true, required: trueproperty :url, Text, required: trueproperty :created_at, DateTimeproperty :updated_at, DateTimeend
  • SAVING DATAapplication.rbdef generate_short_url(long_url@shortcode = random_string 5su = ShortURL.first_or_create({ :url => long_url },{:short_url => @shortcode,:created_at => Time.now,:updated_at => Time.now})get_site_url(su.short_url)end
  • GETTING DATAapplication.rb# root pageget / do# get the current object of all links stored@urls = ShortURL.all;erb :indexendviews/index.erb<h1>Serving <%= @urls.count %> links</h1>
  • GETTING DATAapplication.rbget /:short_url do@URLData = ShortURL.get(params[:short_url])end
  • DIRECTORY STRUCTURE| -- application.rb| -- views-- index.erb-- layout.erb| -- public-- css-- style.css-- javascript| -- lib-- shorturl.rb
  • CONTENT TYPESReturn content in a number of formats, includingJSONXMLHTMLmonkeh$ gem install jsonMay need some more gems to process
  • CONTENT TYPEapplication.rbget / doif params[:url] and not params[:url].empty?@shortURL = generate_short_url(params[:url])content_type :json{:original_url => params[:url],:short_url => @shortURL}.to_jsonelse# get the current count of all links stored@urls = ShortURL.all;erb :indexendend
  • TESTING
  • WHY?
  • BECAUSE!
  • TESTING GEMSmonkeh$ gem install rspecmonkeh$ gem install rackmonkeh$ gem install rack/test
  • TESTING WITH RSPECspec/application_rspec.rbrequire_relative ../application.rbrequire rack/testset :environment, :testdef appSinatra::Applicationenddescribe URL Shortening Service doinclude Rack::Test::Methodsit "should load the home page" doget /last_response.should be_okendend
  • AUTO TESTINGmonkeh$ gem install ZenTest
  • AUTO TESTING NOTIFICATIONSmonkeh$ gem install autotest-growlmonkeh$ gem install autotest-fsevent
  • DIRECTORY STRUCTURE| -- application.rb| -- views-- index.erb-- layout.erb| -- public-- css-- style.css-- javascript| -- lib-- shorturl.rb| -- spec-- application_rspec.rb
  • http://gembundler.com/v1.3/gemfile.htmlmonkeh$ gem install bundler
  • Gemfilesource https://rubygems.orggem sinatragem jsongem dm-coregem dm-migrationsgem dm-postgres-adaptergroup :development dogem shotgunendgroup :production dogem thinendGEMFILE
  • monkeh$ bundle installmonkeh$ git add Gemfile Gemfile.lockBUNDLE TIME
  • CONFIG.RUMany reasons to use, but especially if..you are deploying to a different Rack handlerHerokuPassenger
  • config.rurequire ./application.rbrun Sinatra::ApplicationCONFIG.RU
  • Procfileweb: bundle exec thin -R config.ru start -p $PORT -e $RACK_ENVPROCFILE
  • HEROKU DEPLOYMENTmonkeh$ git initmonkeh$ git add .monkeh$ git commit -m "Initial commit"
  • monkeh$ heroku create urlshrinkappCreating urlshrinkapp... done, stack is cedarhttp://urlshrinkapp.herokuapp.com/ | git@heroku.com:urlshrinkapp.gitGit remote heroku addedHEROKU
  • monkeh$ git push heroku masterTotal 19 (delta 2), reused 0 (delta 0)-----> Ruby/Rack app detected-----> Installing dependencies using Bundler version 1.3.2Running: bundle install --without development:test --path vendor/bundle --binstubsvendor/bundle/bin --deploymentFetching gem metadata from https://rubygems.org/.........Fetching gem metadata from https://rubygems.org/..Installing data_objects (0.10.13)Installing dm-core (1.2.0)Installing dm-do-adapter (1.2.0)Installing dm-migrations (1.2.0)Installing do_postgres (0.10.13)Installing dm-postgres-adapter (1.2.0)Installing eventmachine (1.0.3)Installing json (1.8.0)Installing rack (1.5.2)Installing rack-protection (1.5.0)Installing tilt (1.4.1)Installing sinatra (1.4.2)Using bundler (1.3.2)Your bundle is complete! It was installed into ./vendor/bundleCleaning up the bundler cache.-----> Discovering process typesProcfile declares types -> webDefault types for Ruby/Rack -> console, rake-----> Compiled slug size: 3.0MB-----> Launching... done, v4http://urlshrinkapp.herokuapp.com deployed to HerokuTo git@heroku.com:urlshrinkapp.git* [new branch] master -> masterHEROKU
  • monkeh$ heroku addons:add heroku-postgresql:devAdding heroku-postgresql:dev on urlshrinkapp... done, v5 (free)Attached as HEROKU_POSTGRESQL_BROWN_URLDatabase has been created and is availableheroku pg:promote HEROKU_POSTGRESQL_BROWN_URLPromoting HEROKU_POSTGRESQL_BROWN_URL to DATABASE_URL... doneHEROKU
  • monkeh$ heroku run consoleRunning `console` attached to terminal... up, run.2858irb(main):001:0> require ./application.rb=> trueirb(main):002:0> DataMapper.auto_upgrade!=> #<DataMapper::DescendantSet:0x000000035aacf0@descendants=#<DataMapper::SubjectSet:0x000000035aaca0@entries=#<DataMapper::OrderedSet:0x000000035aac78@cache=#<DataMapper::SubjectSet::NameCache:0x000000035aac50@cache={"ShortURL"=>0}>, @entries=[ShortURL]>>>irb(main):003:0> exitHEROKU
  • monkeh$ heroku openOpening urlshrinkapp... doneHEROKU
  • DIRECTORY STRUCTURE| -- application.rb| -- views-- index.erb-- layout.erb| -- public-- css-- style.css-- javascript| -- Gemfile| -- lib| -- spec| -- config.ru| -- Procfile
  • BACK TO SINATRA
  • USEFUL LINKShttp://sinatrarb.comhttps://github.com/sinatra/sinatrahttp://rvm.io
  • == Sinatra has ended his set (crowd applauds)