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.rb
usingApp.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
get
in sinatra.curl -v http://localhost:9292
will show the request type ofget '/'
-
POST equivalent to
post
in sinatra, post can be used to submit formspost '/' do 'Hello World' end curl -X POST -v -d "" http://localhost:9292
-
PUT equivalent to
put
in sinatra.put '/' do 'Hello World' end curl -X PUT -v -d "" http://localhost:9292
-
DELETE equivalent to
delete
delete '/' 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}"
end
try 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}"
end
HAML
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
end
views/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
= yield
There 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"
end
Stores 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 << file
and 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'
end
render 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
end
Making 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"
end
http://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
end
views/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
end
views/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