Dependencies: ruby
gem install sinatra
Bare Minimum:
-
app.rb => contains application logic*
require 'sinatra/base' #Application inheriting sinatra's base class class App < Sinatra::Base #Routes #get is a request with relative url and a block to execute get '/' do 'Hello World' end end
-
config.ru => rack app for configuring sinatra app
require './app' run App
-
Or start the application in the same
app.rbusingApp.run!
Running the App:
rackup
rackup will automatically lookup config.ru and starts the application using webbrick
To provide a custom port for rackup use rackup config.ru --port=4567
verbs in http GET
-
GET equivalent to
getin sinatra.curl -v http://localhost:9292will show the request type ofget '/' -
POST equivalent to
postin sinatra, post can be used to submit formspost '/' do 'Hello World' end curl -X POST -v -d "" http://localhost:9292 -
PUT equivalent to
putin sinatra.put '/' do 'Hello World' end curl -X PUT -v -d "" http://localhost:9292 -
DELETE equivalent to
deletedelete '/' do 'Hello World' end curl -X DELETE -v -d "" http://localhost:9292
Dynamic Routes:
Routes built dynamically using variables inside requests
get "/hello/:name" do |app_name|
"Hello #{app_name}"
endtry visiting: http://localhost:9292/your_name
Optional variables in routes:
#here lname is optional in the request
get "/hello/:fname/?:lname?" do |f, l|
"Hello #{f} #{l}"
endHAML and ERB are popular templating langugaes for sinatra
Refreshing views|templates does not require rackup to reboot, because there is no ruby code being changed
Templates reside in views folder of the application
app.rb
IMAGES = [
{ title: "Utopia", url: "http://www.paradise-engineering.com/utopia/utopia.jpg" },
{ title: "Alaska", url: "http://www.travelalaska.com/~/media/Images/Travel%20Alaska/Content/HomePage/ChugachMountains.jpg" },
{ title: "Unknown", url: "http://www.beautifullife.info/wp-content/uploads/2010/12/31/the-unknown.jpg" }
]
get '/images/:id' do |index|
index = index.to_i
@image = IMAGES[index]
haml :'images/show', layout:true
endviews/images/show.haml
%h1 Image: #{@image[:title]}
%p
%img{src: @image[:url]}views/layout.haml
!!! 5
%html
%head
%meta(charset="utf-8")
%title Exhibit
%body
= yieldThere are 2 different types of filters, and they act as callback's that hook into a request execution.
before block is executed before each and every request, useful for logging and other preq stuff.
after block is executed after each and every request
Instance variables passed inside before and after blocks are shared with remaining requests
Filters specific to only particular requests using regular expressions, ex. only do something for images request's
before /images/ do
@message = "images specific requests"
endStores temporary data over the life time of a session
Example to store user data from form to session variables:
-
enable sessions:
enable :sessions -
form for user to enter data, post data and store that data as session variable
app.rb:
get '/sessions/new' do erb :"sessions/new" end post '/sessions' do #assign height from form into params to session variable called height session[:height] = params[:height] #puts request.inspect end before do @user = 'Ashrith' #make session variable global for all requests @height = session[:height] puts '===> Entering request' end
views/sessions/new.erb
<form action='/sessions' method='post'> <p> <input type='text' name='height' placeholder='what is your height?' /> cm </p> <p> <input type='submit' value='store my height information' /> </p> </form>
views/layout.rb
<!doctype html> <html> <head> <meta charset="utf-8" /> <title>Exhibit</title> </head> <body> <h1>Using ERB layout.</h1> <p>The current user is <%= @user %>.</p> <ul> <li> <a href="/sessions/new">New Session</a> </li> <li> <!-- session variable --> <%= @height %> </li> </ul> <% if @message %> <p>You have message:</p> <blockquote> <%= @message %> </blockquote> <% end %> <%= yield %> </body> </html>
Sinatra has logging inbuilt
-
Enable logging using
enable :logging -
Then use logging as so:
logger.info 'info level message' logger.debug 'debug level message' logger.warn 'warn level message' logger.error 'error level message' logger.fatal 'fatal level message'
The inbuilt logger has no ability to write out to file, to do so use comphrensive logging utility like log4r
config.ru
require 'log4r'
logger = Log4r::Logger.new 'app'
logger.outputters << Log4r::Outputter.stderr
file = Log4r::FileOutputter.new('app-file', :filename => 'log/app.log')
file.formatter = Log4r::PatternFormatter.new(:pattern => "[%l] %d :: %m")
logger.outputters << fileand then disable default logging of sinatra by removing enable :logging and instantiate log4r logger object like so before using it:
before do
@user = 'Ashrith'
#make session variable global for all requests
@height = session[:height]
logger = Log4r::Logger['app']
logger.info '===> Entering request'
endrender image directly using sinatra, ?:format? will store the format of the file extension and can be passed as a block param
#support formats, render image
get "/images/:index.?:format?" do |index, format|
index = index.to_i #routes are strings
@index = index
@image = IMAGES[index]
if format == 'jpeg'
content_type :jpeg # image/jpeg
# send file uses path relative to this file
send_file "images/#{index}.jpeg"
else
#this is how you send folders as reference to templates 'views/images/show.haml'
#also specifying the layout file from 'views/layout.haml'
haml :"images/show", layout: true
end
endMaking a image downloadle using attachment
#downloadable images
get "/images/:index/download" do |index|
@image = IMAGES[index.to_i]
# method that forces the app to make it a downloadable file, rather than just serving it inline
attachment @image[:title]
send_file "images/#{index}.jpeg"
endhttp://www.sinatrarb.com/configuration.html
Render PDF'S
Steps for using extensions:
- Install the extension
gem install dberkom-sinatra-prawn -s http://gems.github.com - Require the lib
require sinatra/prawn - register the extensiosn
register Sinatra::Prawn
Sample Code for rendeing pdf with prawn:
app.rb
#Prawn pdf rendering
get "/sample.pdf" do
# attachment #make this file downloadable instead of printing it inline
content_type :pdf
@message = "Hello from PDF!"
#use prawn template to generate pdf
prawn :samplepdf
endviews/samplepdf.prawn
pdf.text @message
# "This is sample PDF using the Sinatra::Prawn extension!"
More extensions: http://www.sinatrarb.com/extensions-wild.html
Gems used: data_mapper, sinatra-contrib (contains Namespace extension) and dm-sqlite-adapter (contains datamapper sqlite adapter)
db.rb
env = ENV['RACK_ENV'] || 'development'
url = "sqlite://#{Dir.pwd}/db/#{env}.sqlite3"
#mysql_url = "mysql://user_name:password@localhost/db_name"
DataMapper.setup :default, url
#Class to map database
class Image
include DataMapper::Resource
property :id, Serial
property :title, String
property :url, String, length: 0..250
property :description, Text
end
DataMapper.finalize
DataMapper.auto_upgrade!app.rb
namespace "/images" do
get do #/images
@images = Image.all #fetch all images from database
haml :"/images/index", layout_engine: :erb
end
get "/:id" do |id|
@image = Image.get(id) #fetch image from db
haml %s(images/show), layout_engine: :erb
end
post do #/images
@image = Image.create params[:image]
redirect "/images"
end
endviews/images/index.haml
%h1 Images
-if @images.count == 0
%h4 You have no images.
-@images.each do |image|
%h2
%a{href: "/images/#{image.id}"}=image[:title]
%p
%img{src: image[url], width: 40}
%blockquote=image[:description]
%h2 Store a new image
%form.row(action="/images" method="post")
%p.six.columns
%label Title
%input(type="text" placeholder="Enter a title" name="image[title]")
%p.six.columns
%label URL
%input(type="url" placeholder="Enter a url" name="image[url]")
%p.twelve.columns
%label Description
%textarea(placeholder="Enter a quick description" rows="3" name="image[description")
%p.twelve.columns
%input.button(type="submit" value="Create Image")views/images/show.haml
%h1 Image: #{@image.title}
%p
%img{src: @image.url}
%p
%a{href: "#{@index}/download"} Download this image