SlideShare a Scribd company logo
1 of 112
Download to read offline
Classy Web Development with

Ruby, Sinatra
and Heroku
Get a site online in five minutes
            or less.
But first...
serve
serve
Get a site online* in 5 seconds!
serve
Get a site online* in 5 seconds!
                         *localhost
rob$ serve
rob$ serve
[2010-03-23 11:35:38] INFO   WEBrick 1.3.1
[2010-03-23 11:35:38] INFO   ruby 1.8.7 (2008-08-11)
[2010-03-23 11:35:38] INFO   Serve::Server#start: pid=63741 port=4000
rob$ serve
[2010-03-23 11:35:38] INFO   WEBrick 1.3.1
[2010-03-23 11:35:38] INFO   ruby 1.8.7 (2008-08-11)
[2010-03-23 11:35:38] INFO   Serve::Server#start: pid=63741 port=4000
rob$ serve
[2010-03-23 11:35:38] INFO   WEBrick 1.3.1
[2010-03-23 11:35:38] INFO   ruby 1.8.7 (2008-08-11)
[2010-03-23 11:35:38] INFO   Serve::Server#start: pid=63741 port=4000




             http://localhost:4000
rob$ serve
[2010-03-23 11:35:38] INFO   WEBrick 1.3.1
[2010-03-23 11:35:38] INFO   ruby 1.8.7 (2008-08-11)
[2010-03-23 11:35:38] INFO   Serve::Server#start: pid=63741 port=4000




             http://localhost:4000
rob$ serve
[2010-03-23 11:35:38] INFO WEBrick 1.3.1
[2010-03-23 11:35:38] INFO ruby 1.8.7 (2008-08-11)
[2010-03-23 11:35:38] INFO Serve::Server#start: pid=63741 port=4000
localhost - - [23/Mar/2010:11:54:40 PDT] "GET / HTTP/1.1" 200 0
- -> /
localhost - - [23/Mar/2010:11:54:40 PDT] "GET /stylesheets/reset-
fonts.css HTTP/1.1" 200 0
http://localhost:4000/ -> /stylesheets/reset-fonts.css
localhost - - [23/Mar/2010:11:54:40 PDT] "GET /stylesheets/
screen.css HTTP/1.1" 200 0
http://localhost:4000/ -> /stylesheets/screen.css
localhost - - [23/Mar/2010:11:54:40 PDT] "GET /stylesheets/
syntax.css HTTP/1.1" 200 0
http://localhost:4000/ -> /stylesheets/syntax.css
localhost - - [23/Mar/2010:11:54:40 PDT] "GET /javascripts/
prototype.js HTTP/1.1" 200 0
http://localhost:4000/ -> /javascripts/prototype.js
localhost - - [23/Mar/2010:11:54:40 PDT] "GET /javascripts/
effects.js HTTP/1.1" 200 0
http://localhost:4000/ -> /javascripts/effects.js
localhost - - [23/Mar/2010:11:54:40 PDT] "GET /javascripts/stack.js
HTTP/1.1" 200 0
http://localhost:4000/ -> /javascripts/stack.js
[2010-03-23 11:54:41] ERROR `/favicon.ico' not found.
localhost - - [23/Mar/2010:11:54:41 PDT] "GET /favicon.ico HTTP/1.1"
404 281
demo
 serve
questions?
Sinatra
hi.rb
-----
require 'rubygems'
require 'sinatra'
get '/hi' do
  "Hello World!"
end
rob$ ruby hi.rb
rob$ ruby hi.rb
== Sinatra/0.9.4 has taken the stage on 4567 for development with
backup from Thin
>> Thin web server (v1.2.4 codename Flaming Astroboy)
>> Maximum connections set to 1024
>> Listening on 0.0.0.0:4567, CTRL+C to stop
rob$ ruby hi.rb
== Sinatra/0.9.4 has taken the stage on 4567 for development with
backup from Thin
>> Thin web server (v1.2.4 codename Flaming Astroboy)
>> Maximum connections set to 1024
>> Listening on 0.0.0.0:4567, CTRL+C to stop
rob$ ruby hi.rb
== Sinatra/0.9.4 has taken the stage on 4567 for development with
backup from Thin
>> Thin web server (v1.2.4 codename Flaming Astroboy)
>> Maximum connections set to 1024
>> Listening on 0.0.0.0:4567, CTRL+C to stop


             http://localhost:4567
hi.rb
-----
require 'rubygems'
require 'sinatra'
get '/hi' do
  "Hello World!"
end
rob$ ruby hi.rb
== Sinatra/0.9.4 has taken the stage on 4567 for development with
backup from Thin
>> Thin web server (v1.2.4 codename Flaming Astroboy)
>> Maximum connections set to 1024
>> Listening on 0.0.0.0:4567, CTRL+C to stop


           http://localhost:4567/hi
rob$ ruby hi.rb
== Sinatra/0.9.4 has taken the stage on 4567 for development with
backup from Thin
>> Thin web server (v1.2.4 codename Flaming Astroboy)
>> Maximum connections set to 1024
>> Listening on 0.0.0.0:4567, CTRL+C to stop


           http://localhost:4567/hi
demo
sinatra/hi
require 'rubygems'
require 'sinatra'
get '/hi' do
  "Hello World!"
end
require 'rubygems'   Ruby package manager
require 'sinatra'
get '/hi' do
  "Hello World!"
end
require 'rubygems'   Ruby package manager
require 'sinatra'    Sinatra package (gem)
get '/hi' do
  "Hello World!"
end
require 'rubygems'   Ruby package manager
require 'sinatra'    Sinatra package (gem)
get '/hi' do         GET request to /hi
  "Hello World!"
end
require 'rubygems'   Ruby package manager
require 'sinatra'    Sinatra package (gem)
get '/hi' do         GET request to /hi
  "Hello World!"     Respond with text
end
get '/hi' do
  "Hello World!"
end
}
get '/hi' do
  "Hello World!"       “block”
end
}
get '/hi' do           Whatever is returned from
  "Hello World!"       the block is sent to the
end                    browser
Where’s the return?
In Ruby, if you don’t say “return,”
            it’s implied.
In Ruby, if you don’t say “return”
            it’s implied.


The last statement in a block is
       always returned.
get '/hi' do
  "Hello World!"
end
=
get '/hi' do
  "Hello World!"
end
=
get '/hi' do           get '/hi' do
  "Hello World!"         return "Hello World!"
end                    end
A slightly more complex example
beta.rb
-------
require 'rubygems'
require 'sinatra'

get '/' do
  html = '<p>Welcome! Leave your email address for more info!</p>'
  html += '<form method="post" action="/submit">'
  html += '<input type="text" name="email" /><input type="submit" /></form>'
  return html
end

post '/submit' do
  html = '<p>Thank you for your submission!</p>'
  html += '<p>We will email ' + params['email']
  html += ' when we are ready to launch!</p>'
  return html
end
demo
sinatra/beta1
Views
`-- beta.rb



|-- beta.rb
`-- views
    |-- index.erb
    `-- submit.erb
erb
Embedded Ruby
beta.rb
-------
require 'rubygems'
require 'sinatra'

get '/' do
  erb :index
end

post '/submit' do
  erb :submit
end
beta.rb
-------
require 'rubygems'
require 'sinatra'

get '/' do
  erb :index
end

post '/submit' do
  erb :submit
end




views/index.erb
---------------
<p>Welcome! Leave your email address for more info!</p>
<form method="post" action="/submit">
  <input type="text" name="email" />
  <input type="submit" />
</form>
beta.rb
-------
require 'rubygems'
require 'sinatra'

get '/' do
  erb :index
end

post '/submit' do
  erb :submit
end




views/index.erb
---------------
<p>Welcome! Leave your email address for more info!</p>
<form method="post" action="/submit">
  <input type="text" name="email" />
  <input type="submit" />
</form>



views/submit.erb
----------------
<p>Thank you for your submission!</p>
<p>We will email <%= params['email'] %> when we are ready to launch!</p>
demo
sinatra/beta2
Layouts
|-- beta.rb
`-- views
    |-- index.erb
    |-- layout.erb
    `-- submit.erb
views/layout.rb
---------------
<!DOCTYPE html>
<html>
<head>
  <title>Beta Info</title>
</head>
<body>
  <%= yield %>
</body>
</html>
views/layout.rb
---------------
<!DOCTYPE html>
<html>
<head>
  <title>Beta Info</title>
</head>
<body>
  <%= yield %>
</body>
</html>




views/index.erb
---------------
<p>Welcome! Leave your email address for more info!</p>
<form method="post" action="/submit">
  <input type="text" name="email" />
  <input type="submit" />
</form>
views/layout.rb
---------------
<!DOCTYPE html>
<html>
<head>
  <title>Beta Info</title>
</head>
<body>
  <%= yield %>
</body>
</html>




views/index.erb
---------------
<p>Welcome! Leave your email address for more info!</p>
<form method="post" action="/submit">
  <input type="text" name="email" />
  <input type="submit" />
</form>
demo
sinatra/beta3
Static Content
 Images, stylesheets and Javascript
|-- beta.rb
`-- views
    |-- index.erb
    |-- layout.erb
    `-- submit.erb
|-- beta.rb
|-- public
`-- views
    |-- index.erb
    |-- layout.erb
    `-- submit.erb
|--   beta.rb
|--   public
|     `-- stylesheets
|         `-- shared.css
`--   views
      |-- index.erb
      |-- layout.erb
      `-- submit.erb
demo
sinatra/beta4
So
So
1. Every URL you want to respond to goes in your .rb file
So
1. Every URL you want to respond to goes in your .rb file

2. Pages themselves go in /views as .erb files
So
1. Every URL you want to respond to goes in your .rb file

2. Pages themselves go in /views as .erb files

3. Wrapping layout goes in /views/layout.erb
So
1. Every URL you want to respond to goes in your .rb file

2. Pages themselves go in /views as .erb files

3. Wrapping layout goes in /views/layout.erb

4. Static files go in /public
But
But
If all you have is static web pages, no need to
   add every path to your sinatra .rb file and
             copy the code to /views
But
If all you have is static web pages, no need to
   add every path to your sinatra .rb file and
             copy the code to /views

           Just put them in /public
But
If all you have is static web pages, no need to
   add every path to your sinatra .rb file and
             copy the code to /views

           Just put them in /public

   The .rb file is more for dynamic URLs or
      gathering form fields for use later
Dynamic URLs?
dynamic.rb
----------
require 'rubygems'
require 'sinatra'

get '/' do
  'This is the homepage'
end

get '/:city' do
  'This is the ' + params['city'] + ' homepage'
end
demo
sinatra/dynamic
questions?
Heroku
Kind of like EC2 but specific to
Ruby-based web applications
Run your application/website
          for free
Heroku relies on Git.
Git
Like subversion, but more powerful (and complex)
rob$ git init .
rob$ git init .
Initialized empty Git repository in /Users/rob/Dropbox/Active
University/sinatra/heroku1/.git/
rob$ git init .
Initialized empty Git repository in /Users/rob/Dropbox/Active
University/sinatra/heroku1/.git/

rob$ git add .
rob$ git init .
Initialized empty Git repository in /Users/rob/Dropbox/Active
University/sinatra/heroku1/.git/

rob$ git add .

rob$ git commit -m ‘First commit’
rob$ git init .
Initialized empty Git repository in /Users/rob/Dropbox/Active
University/sinatra/heroku1/.git/

rob$ git add .

rob$ git commit -m ‘First commit’
[master (root-commit) d2f7469] First commit
 5 files changed, 31 insertions(+), 0 deletions(-)
 create mode 100644 beta.rb
 create mode 100644 public/stylesheets/shared.css
 create mode 100644 views/index.erb
 create mode 100644 views/layout.erb
 create mode 100644 views/submit.erb
Our app is version controlled
rob$ heroku create
rob$ heroku create
Creating blooming-sunrise-28... done!
Created http://blooming-sunrise-28.heroku.com/ |
git@heroku.com:blooming-sunrise-28.git
Git remote heroku added
rob$ heroku create
Creating blooming-sunrise-28... done!
Created http://blooming-sunrise-28.heroku.com/ |
git@heroku.com:blooming-sunrise-28.git
Git remote heroku added

rob$ git push heroku master
rob$ heroku create
Creating blooming-sunrise-28... done!
Created http://blooming-sunrise-28.heroku.com/ |
git@heroku.com:blooming-sunrise-28.git
Git remote heroku added

rob$ git push heroku master
Counting objects: 10, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (8/8), done.
Writing objects: 100% (10/10), 1009 bytes, done.
Total 10 (delta 0), reused 0 (delta 0)

-----> Heroku receiving push
 !     Heroku push rejected, no Rails or Rack app detected.

error: hooks/pre-receive exited with error code 1
To git@heroku.com:blooming-sunrise-28.git
 ! [remote rejected] master -> master (pre-receive hook declined)
error: failed to push some refs to 'git@heroku.com:blooming-
sunrise-28.git'
demo
sinatra/heroku1
One thing missing
One thing missing


config.ru
|--   beta.rb
|--   config.ru
|--   public
|     `-- stylesheets
|         `-- shared.css
`--   views
      |-- index.erb
      |-- layout.erb
      `-- submit.erb
config.ru
---------
require 'beta'
run Sinatra::Application
rob$ git add .
rob$ git add .

rob$ git commit -m 'Added config.ru file for heroku'
rob$ git add .

rob$ git commit -m 'Added config.ru file for heroku'
[master 7b8ab4f] Added config.ru file for heroku
 1 files changed, 2 insertions(+), 0 deletions(-)
 create mode 100644 config.ru
rob$ git add .

rob$ git commit -m 'Added config.ru file for heroku'
[master 7b8ab4f] Added config.ru file for heroku
 1 files changed, 2 insertions(+), 0 deletions(-)
 create mode 100644 config.ru

rob$ git push heroku master
rob$ git add .

rob$ git commit -m 'Added config.ru file for heroku'
[master 7b8ab4f] Added config.ru file for heroku
 1 files changed, 2 insertions(+), 0 deletions(-)
 create mode 100644 config.ru

rob$ git push heroku master
Counting objects: 13, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (10/10), done.
Writing objects: 100% (13/13), 1.27 KiB, done.
Total 13 (delta 1), reused 0 (delta 0)

-----> Heroku receiving push
-----> Sinatra app detected
       Compiled slug size is 4K
-----> Launching..... done
       http://blooming-sunrise-28.heroku.com deployed to Heroku

To git@heroku.com:blooming-sunrise-28.git
 * [new branch]      master -> master
demo
sinatra/heroku2
So
So
1. Get your app working in development
So
1. Get your app working in development

2. Add a config.ru file
So
1. Get your app working in development

2. Add a config.ru file

3. git init . (only the first time)
So
1. Get your app working in development

2. Add a config.ru file

3. git init . (only the first time)

4. git add .
So
1. Get your app working in development

2. Add a config.ru file

3. git init . (only the first time)

4. git add .

5. git commit -m ‘message’
So
1. Get your app working in development

2. Add a config.ru file

3. git init . (only the first time)

4. git add .

5. git commit -m ‘message’

6. heroku create (only the first time)
So
1. Get your app working in development

2. Add a config.ru file

3. git init . (only the first time)

4. git add .

5. git commit -m ‘message’

6. heroku create (only the first time)

7. git push heroku master
questions?
Installation
Ruby 1.8.6 or higher
http://ruby-lang.org

Rubygems 1.3.6
http://rubyforge.org/projects/rubygems

Get Serve, Sinatra and Heroku gems
gem install serve sinatra heroku

Git
http://git-scm.com/download
Resources
Ruby Homepage
http://ruby-lang.org

Sinatra Homepage
http://www.sinatrarb.com

Heroku Homepage
http://heroku.com

Git Homepage
http://git-scm.com

Example Code
http://empty-journey-91.heroku.com/
The End

More Related Content

Recently uploaded

[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdfhans926745
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Enterprise Knowledge
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxKatpro Technologies
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel Araújo
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonetsnaman860154
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsEnterprise Knowledge
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j
 
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...gurkirankumar98700
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEarley Information Science
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityPrincipled Technologies
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Paola De la Torre
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking MenDelhi Call girls
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxMalak Abu Hammad
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slidespraypatel2
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking MenDelhi Call girls
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Scriptwesley chun
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
 

Recently uploaded (20)

[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
 
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slides
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 

Featured

2024 State of Marketing Report – by Hubspot
2024 State of Marketing Report – by Hubspot2024 State of Marketing Report – by Hubspot
2024 State of Marketing Report – by HubspotMarius Sescu
 
Everything You Need To Know About ChatGPT
Everything You Need To Know About ChatGPTEverything You Need To Know About ChatGPT
Everything You Need To Know About ChatGPTExpeed Software
 
Product Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage EngineeringsProduct Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage EngineeringsPixeldarts
 
How Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental HealthHow Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental HealthThinkNow
 
AI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdfAI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdfmarketingartwork
 
PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024Neil Kimberley
 
Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)contently
 
How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024Albert Qian
 
Social Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsSocial Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsKurio // The Social Media Age(ncy)
 
Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Search Engine Journal
 
5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summarySpeakerHub
 
ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd Clark Boyd
 
Getting into the tech field. what next
Getting into the tech field. what next Getting into the tech field. what next
Getting into the tech field. what next Tessa Mero
 
Google's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentGoogle's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentLily Ray
 
Time Management & Productivity - Best Practices
Time Management & Productivity -  Best PracticesTime Management & Productivity -  Best Practices
Time Management & Productivity - Best PracticesVit Horky
 
The six step guide to practical project management
The six step guide to practical project managementThe six step guide to practical project management
The six step guide to practical project managementMindGenius
 
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...RachelPearson36
 

Featured (20)

2024 State of Marketing Report – by Hubspot
2024 State of Marketing Report – by Hubspot2024 State of Marketing Report – by Hubspot
2024 State of Marketing Report – by Hubspot
 
Everything You Need To Know About ChatGPT
Everything You Need To Know About ChatGPTEverything You Need To Know About ChatGPT
Everything You Need To Know About ChatGPT
 
Product Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage EngineeringsProduct Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage Engineerings
 
How Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental HealthHow Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental Health
 
AI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdfAI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdf
 
Skeleton Culture Code
Skeleton Culture CodeSkeleton Culture Code
Skeleton Culture Code
 
PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024
 
Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)
 
How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024
 
Social Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsSocial Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie Insights
 
Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024
 
5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary
 
ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd
 
Getting into the tech field. what next
Getting into the tech field. what next Getting into the tech field. what next
Getting into the tech field. what next
 
Google's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentGoogle's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search Intent
 
How to have difficult conversations
How to have difficult conversations How to have difficult conversations
How to have difficult conversations
 
Introduction to Data Science
Introduction to Data ScienceIntroduction to Data Science
Introduction to Data Science
 
Time Management & Productivity - Best Practices
Time Management & Productivity -  Best PracticesTime Management & Productivity -  Best Practices
Time Management & Productivity - Best Practices
 
The six step guide to practical project management
The six step guide to practical project managementThe six step guide to practical project management
The six step guide to practical project management
 
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
 

Classy Web Development With Ruby, Sinatra And Heroku

  • 1. Classy Web Development with Ruby, Sinatra and Heroku Get a site online in five minutes or less.
  • 4. serve Get a site online* in 5 seconds!
  • 5. serve Get a site online* in 5 seconds! *localhost
  • 7. rob$ serve [2010-03-23 11:35:38] INFO WEBrick 1.3.1 [2010-03-23 11:35:38] INFO ruby 1.8.7 (2008-08-11) [2010-03-23 11:35:38] INFO Serve::Server#start: pid=63741 port=4000
  • 8. rob$ serve [2010-03-23 11:35:38] INFO WEBrick 1.3.1 [2010-03-23 11:35:38] INFO ruby 1.8.7 (2008-08-11) [2010-03-23 11:35:38] INFO Serve::Server#start: pid=63741 port=4000
  • 9. rob$ serve [2010-03-23 11:35:38] INFO WEBrick 1.3.1 [2010-03-23 11:35:38] INFO ruby 1.8.7 (2008-08-11) [2010-03-23 11:35:38] INFO Serve::Server#start: pid=63741 port=4000 http://localhost:4000
  • 10. rob$ serve [2010-03-23 11:35:38] INFO WEBrick 1.3.1 [2010-03-23 11:35:38] INFO ruby 1.8.7 (2008-08-11) [2010-03-23 11:35:38] INFO Serve::Server#start: pid=63741 port=4000 http://localhost:4000
  • 11. rob$ serve [2010-03-23 11:35:38] INFO WEBrick 1.3.1 [2010-03-23 11:35:38] INFO ruby 1.8.7 (2008-08-11) [2010-03-23 11:35:38] INFO Serve::Server#start: pid=63741 port=4000 localhost - - [23/Mar/2010:11:54:40 PDT] "GET / HTTP/1.1" 200 0 - -> / localhost - - [23/Mar/2010:11:54:40 PDT] "GET /stylesheets/reset- fonts.css HTTP/1.1" 200 0 http://localhost:4000/ -> /stylesheets/reset-fonts.css localhost - - [23/Mar/2010:11:54:40 PDT] "GET /stylesheets/ screen.css HTTP/1.1" 200 0 http://localhost:4000/ -> /stylesheets/screen.css localhost - - [23/Mar/2010:11:54:40 PDT] "GET /stylesheets/ syntax.css HTTP/1.1" 200 0 http://localhost:4000/ -> /stylesheets/syntax.css localhost - - [23/Mar/2010:11:54:40 PDT] "GET /javascripts/ prototype.js HTTP/1.1" 200 0 http://localhost:4000/ -> /javascripts/prototype.js localhost - - [23/Mar/2010:11:54:40 PDT] "GET /javascripts/ effects.js HTTP/1.1" 200 0 http://localhost:4000/ -> /javascripts/effects.js localhost - - [23/Mar/2010:11:54:40 PDT] "GET /javascripts/stack.js HTTP/1.1" 200 0 http://localhost:4000/ -> /javascripts/stack.js [2010-03-23 11:54:41] ERROR `/favicon.ico' not found. localhost - - [23/Mar/2010:11:54:41 PDT] "GET /favicon.ico HTTP/1.1" 404 281
  • 15.
  • 16.
  • 19. rob$ ruby hi.rb == Sinatra/0.9.4 has taken the stage on 4567 for development with backup from Thin >> Thin web server (v1.2.4 codename Flaming Astroboy) >> Maximum connections set to 1024 >> Listening on 0.0.0.0:4567, CTRL+C to stop
  • 20. rob$ ruby hi.rb == Sinatra/0.9.4 has taken the stage on 4567 for development with backup from Thin >> Thin web server (v1.2.4 codename Flaming Astroboy) >> Maximum connections set to 1024 >> Listening on 0.0.0.0:4567, CTRL+C to stop
  • 21. rob$ ruby hi.rb == Sinatra/0.9.4 has taken the stage on 4567 for development with backup from Thin >> Thin web server (v1.2.4 codename Flaming Astroboy) >> Maximum connections set to 1024 >> Listening on 0.0.0.0:4567, CTRL+C to stop http://localhost:4567
  • 23. rob$ ruby hi.rb == Sinatra/0.9.4 has taken the stage on 4567 for development with backup from Thin >> Thin web server (v1.2.4 codename Flaming Astroboy) >> Maximum connections set to 1024 >> Listening on 0.0.0.0:4567, CTRL+C to stop http://localhost:4567/hi
  • 24. rob$ ruby hi.rb == Sinatra/0.9.4 has taken the stage on 4567 for development with backup from Thin >> Thin web server (v1.2.4 codename Flaming Astroboy) >> Maximum connections set to 1024 >> Listening on 0.0.0.0:4567, CTRL+C to stop http://localhost:4567/hi
  • 26. require 'rubygems' require 'sinatra' get '/hi' do "Hello World!" end
  • 27. require 'rubygems' Ruby package manager require 'sinatra' get '/hi' do "Hello World!" end
  • 28. require 'rubygems' Ruby package manager require 'sinatra' Sinatra package (gem) get '/hi' do "Hello World!" end
  • 29. require 'rubygems' Ruby package manager require 'sinatra' Sinatra package (gem) get '/hi' do GET request to /hi "Hello World!" end
  • 30. require 'rubygems' Ruby package manager require 'sinatra' Sinatra package (gem) get '/hi' do GET request to /hi "Hello World!" Respond with text end
  • 31. get '/hi' do "Hello World!" end
  • 32. } get '/hi' do "Hello World!" “block” end
  • 33. } get '/hi' do Whatever is returned from "Hello World!" the block is sent to the end browser
  • 35. In Ruby, if you don’t say “return,” it’s implied.
  • 36. In Ruby, if you don’t say “return” it’s implied. The last statement in a block is always returned.
  • 37. get '/hi' do "Hello World!" end
  • 38. = get '/hi' do "Hello World!" end
  • 39. = get '/hi' do get '/hi' do "Hello World!" return "Hello World!" end end
  • 40. A slightly more complex example
  • 41. beta.rb ------- require 'rubygems' require 'sinatra' get '/' do html = '<p>Welcome! Leave your email address for more info!</p>' html += '<form method="post" action="/submit">' html += '<input type="text" name="email" /><input type="submit" /></form>' return html end post '/submit' do html = '<p>Thank you for your submission!</p>' html += '<p>We will email ' + params['email'] html += ' when we are ready to launch!</p>' return html end
  • 43. Views
  • 44. `-- beta.rb |-- beta.rb `-- views |-- index.erb `-- submit.erb
  • 46. beta.rb ------- require 'rubygems' require 'sinatra' get '/' do erb :index end post '/submit' do erb :submit end
  • 47. beta.rb ------- require 'rubygems' require 'sinatra' get '/' do erb :index end post '/submit' do erb :submit end views/index.erb --------------- <p>Welcome! Leave your email address for more info!</p> <form method="post" action="/submit"> <input type="text" name="email" /> <input type="submit" /> </form>
  • 48. beta.rb ------- require 'rubygems' require 'sinatra' get '/' do erb :index end post '/submit' do erb :submit end views/index.erb --------------- <p>Welcome! Leave your email address for more info!</p> <form method="post" action="/submit"> <input type="text" name="email" /> <input type="submit" /> </form> views/submit.erb ---------------- <p>Thank you for your submission!</p> <p>We will email <%= params['email'] %> when we are ready to launch!</p>
  • 51. |-- beta.rb `-- views |-- index.erb |-- layout.erb `-- submit.erb
  • 52. views/layout.rb --------------- <!DOCTYPE html> <html> <head> <title>Beta Info</title> </head> <body> <%= yield %> </body> </html>
  • 53. views/layout.rb --------------- <!DOCTYPE html> <html> <head> <title>Beta Info</title> </head> <body> <%= yield %> </body> </html> views/index.erb --------------- <p>Welcome! Leave your email address for more info!</p> <form method="post" action="/submit"> <input type="text" name="email" /> <input type="submit" /> </form>
  • 54. views/layout.rb --------------- <!DOCTYPE html> <html> <head> <title>Beta Info</title> </head> <body> <%= yield %> </body> </html> views/index.erb --------------- <p>Welcome! Leave your email address for more info!</p> <form method="post" action="/submit"> <input type="text" name="email" /> <input type="submit" /> </form>
  • 56. Static Content Images, stylesheets and Javascript
  • 57. |-- beta.rb `-- views |-- index.erb |-- layout.erb `-- submit.erb
  • 58. |-- beta.rb |-- public `-- views |-- index.erb |-- layout.erb `-- submit.erb
  • 59. |-- beta.rb |-- public | `-- stylesheets | `-- shared.css `-- views |-- index.erb |-- layout.erb `-- submit.erb
  • 61. So
  • 62. So 1. Every URL you want to respond to goes in your .rb file
  • 63. So 1. Every URL you want to respond to goes in your .rb file 2. Pages themselves go in /views as .erb files
  • 64. So 1. Every URL you want to respond to goes in your .rb file 2. Pages themselves go in /views as .erb files 3. Wrapping layout goes in /views/layout.erb
  • 65. So 1. Every URL you want to respond to goes in your .rb file 2. Pages themselves go in /views as .erb files 3. Wrapping layout goes in /views/layout.erb 4. Static files go in /public
  • 66. But
  • 67. But If all you have is static web pages, no need to add every path to your sinatra .rb file and copy the code to /views
  • 68. But If all you have is static web pages, no need to add every path to your sinatra .rb file and copy the code to /views Just put them in /public
  • 69. But If all you have is static web pages, no need to add every path to your sinatra .rb file and copy the code to /views Just put them in /public The .rb file is more for dynamic URLs or gathering form fields for use later
  • 71. dynamic.rb ---------- require 'rubygems' require 'sinatra' get '/' do 'This is the homepage' end get '/:city' do 'This is the ' + params['city'] + ' homepage' end
  • 75.
  • 76. Kind of like EC2 but specific to Ruby-based web applications
  • 79. Git Like subversion, but more powerful (and complex)
  • 81. rob$ git init . Initialized empty Git repository in /Users/rob/Dropbox/Active University/sinatra/heroku1/.git/
  • 82. rob$ git init . Initialized empty Git repository in /Users/rob/Dropbox/Active University/sinatra/heroku1/.git/ rob$ git add .
  • 83. rob$ git init . Initialized empty Git repository in /Users/rob/Dropbox/Active University/sinatra/heroku1/.git/ rob$ git add . rob$ git commit -m ‘First commit’
  • 84. rob$ git init . Initialized empty Git repository in /Users/rob/Dropbox/Active University/sinatra/heroku1/.git/ rob$ git add . rob$ git commit -m ‘First commit’ [master (root-commit) d2f7469] First commit 5 files changed, 31 insertions(+), 0 deletions(-) create mode 100644 beta.rb create mode 100644 public/stylesheets/shared.css create mode 100644 views/index.erb create mode 100644 views/layout.erb create mode 100644 views/submit.erb
  • 85. Our app is version controlled
  • 87. rob$ heroku create Creating blooming-sunrise-28... done! Created http://blooming-sunrise-28.heroku.com/ | git@heroku.com:blooming-sunrise-28.git Git remote heroku added
  • 88. rob$ heroku create Creating blooming-sunrise-28... done! Created http://blooming-sunrise-28.heroku.com/ | git@heroku.com:blooming-sunrise-28.git Git remote heroku added rob$ git push heroku master
  • 89. rob$ heroku create Creating blooming-sunrise-28... done! Created http://blooming-sunrise-28.heroku.com/ | git@heroku.com:blooming-sunrise-28.git Git remote heroku added rob$ git push heroku master Counting objects: 10, done. Delta compression using up to 2 threads. Compressing objects: 100% (8/8), done. Writing objects: 100% (10/10), 1009 bytes, done. Total 10 (delta 0), reused 0 (delta 0) -----> Heroku receiving push ! Heroku push rejected, no Rails or Rack app detected. error: hooks/pre-receive exited with error code 1 To git@heroku.com:blooming-sunrise-28.git ! [remote rejected] master -> master (pre-receive hook declined) error: failed to push some refs to 'git@heroku.com:blooming- sunrise-28.git'
  • 93. |-- beta.rb |-- config.ru |-- public | `-- stylesheets | `-- shared.css `-- views |-- index.erb |-- layout.erb `-- submit.erb
  • 96. rob$ git add . rob$ git commit -m 'Added config.ru file for heroku'
  • 97. rob$ git add . rob$ git commit -m 'Added config.ru file for heroku' [master 7b8ab4f] Added config.ru file for heroku 1 files changed, 2 insertions(+), 0 deletions(-) create mode 100644 config.ru
  • 98. rob$ git add . rob$ git commit -m 'Added config.ru file for heroku' [master 7b8ab4f] Added config.ru file for heroku 1 files changed, 2 insertions(+), 0 deletions(-) create mode 100644 config.ru rob$ git push heroku master
  • 99. rob$ git add . rob$ git commit -m 'Added config.ru file for heroku' [master 7b8ab4f] Added config.ru file for heroku 1 files changed, 2 insertions(+), 0 deletions(-) create mode 100644 config.ru rob$ git push heroku master Counting objects: 13, done. Delta compression using up to 2 threads. Compressing objects: 100% (10/10), done. Writing objects: 100% (13/13), 1.27 KiB, done. Total 13 (delta 1), reused 0 (delta 0) -----> Heroku receiving push -----> Sinatra app detected Compiled slug size is 4K -----> Launching..... done http://blooming-sunrise-28.heroku.com deployed to Heroku To git@heroku.com:blooming-sunrise-28.git * [new branch] master -> master
  • 101. So
  • 102. So 1. Get your app working in development
  • 103. So 1. Get your app working in development 2. Add a config.ru file
  • 104. So 1. Get your app working in development 2. Add a config.ru file 3. git init . (only the first time)
  • 105. So 1. Get your app working in development 2. Add a config.ru file 3. git init . (only the first time) 4. git add .
  • 106. So 1. Get your app working in development 2. Add a config.ru file 3. git init . (only the first time) 4. git add . 5. git commit -m ‘message’
  • 107. So 1. Get your app working in development 2. Add a config.ru file 3. git init . (only the first time) 4. git add . 5. git commit -m ‘message’ 6. heroku create (only the first time)
  • 108. So 1. Get your app working in development 2. Add a config.ru file 3. git init . (only the first time) 4. git add . 5. git commit -m ‘message’ 6. heroku create (only the first time) 7. git push heroku master
  • 110. Installation Ruby 1.8.6 or higher http://ruby-lang.org Rubygems 1.3.6 http://rubyforge.org/projects/rubygems Get Serve, Sinatra and Heroku gems gem install serve sinatra heroku Git http://git-scm.com/download
  • 111. Resources Ruby Homepage http://ruby-lang.org Sinatra Homepage http://www.sinatrarb.com Heroku Homepage http://heroku.com Git Homepage http://git-scm.com Example Code http://empty-journey-91.heroku.com/