SlideShare a Scribd company logo

Sinatra Tutorial@Rubyconf.TW2011

介紹Sinatra這套Ruby DSL Framework的基礎, 以及如何透過Sinatra輔助Rails

1 of 73
Download to read offline
用Sinatra建置高效能
              與高自訂性的系統
                Mu-Fan Teng@Rubyconf.TW 2011
                   TOMLAN Software Studio




                             1
11年8月26日星期五
About me
       •      鄧慕凡(Mu-Fan Teng)
              •a.k.a: Ryudo
              •http://twitter.com/ryudoawaru
              •Ruby developer since 2007
              •Founder of Tomlan Software Studio.




                                          2
11年8月26日星期五
3
11年8月26日星期五
Agenda
              • Sinatra Introduction
              • Tutorial
              • Rails Metal
              • Production tips


                                   4
11年8月26日星期五
Why Sinatra




                   5
11年8月26日星期五
Load lesser, run faster!
       Rails 3.1預設: 不含project本身約20個middleware




                         6
11年8月26日星期五

Recommended

Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務
Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務
Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務Mu-Fan Teng
 
Ruby程式語言入門導覽
Ruby程式語言入門導覽Ruby程式語言入門導覽
Ruby程式語言入門導覽Mu-Fan Teng
 
Eventmachine Websocket 實戰
Eventmachine Websocket 實戰Eventmachine Websocket 實戰
Eventmachine Websocket 實戰Mu-Fan Teng
 
View 與 Blade 樣板引擎
View 與 Blade 樣板引擎View 與 Blade 樣板引擎
View 與 Blade 樣板引擎Shengyou Fan
 
PHP 語法基礎與物件導向
PHP 語法基礎與物件導向PHP 語法基礎與物件導向
PHP 語法基礎與物件導向Shengyou Fan
 
Composer 套件管理
Composer 套件管理Composer 套件管理
Composer 套件管理Shengyou Fan
 
使用 laravel 的前與後
使用 laravel 的前與後使用 laravel 的前與後
使用 laravel 的前與後Shengyou Fan
 
應用程式佈署
應用程式佈署應用程式佈署
應用程式佈署Shengyou Fan
 

More Related Content

What's hot

開發環境建置
開發環境建置開發環境建置
開發環境建置Shengyou Fan
 
啟動 Laravel 與環境設定
啟動 Laravel 與環境設定啟動 Laravel 與環境設定
啟動 Laravel 與環境設定Shengyou Fan
 
開發環境建置
開發環境建置開發環境建置
開發環境建置Shengyou Fan
 
View 與 Blade 樣板引擎
View 與 Blade 樣板引擎View 與 Blade 樣板引擎
View 與 Blade 樣板引擎Shengyou Fan
 
COSCUP 2016 Laravel 部署工作坊 - 部署指南
COSCUP 2016 Laravel 部署工作坊 - 部署指南COSCUP 2016 Laravel 部署工作坊 - 部署指南
COSCUP 2016 Laravel 部署工作坊 - 部署指南Shengyou Fan
 
Migrations 與 Schema操作
Migrations 與 Schema操作Migrations 與 Schema操作
Migrations 與 Schema操作Shengyou Fan
 
Model 設定與 Seeding
Model 設定與 SeedingModel 設定與 Seeding
Model 設定與 SeedingShengyou Fan
 
Laravel - 系統全攻略(續)
Laravel - 系統全攻略(續)Laravel - 系統全攻略(續)
Laravel - 系統全攻略(續)Vincent Chi
 
開發流程與工具介紹
開發流程與工具介紹開發流程與工具介紹
開發流程與工具介紹Shengyou Fan
 
Route 路由控制
Route 路由控制Route 路由控制
Route 路由控制Shengyou Fan
 
Model 設定與 Seeding
Model 設定與 SeedingModel 設定與 Seeding
Model 設定與 SeedingShengyou Fan
 
Laravel - 系統全攻略
Laravel - 系統全攻略Laravel - 系統全攻略
Laravel - 系統全攻略Vincent Chi
 
Schema & Migration操作
Schema & Migration操作Schema & Migration操作
Schema & Migration操作Shengyou Fan
 
Package 安裝與使用
Package 安裝與使用Package 安裝與使用
Package 安裝與使用Shengyou Fan
 

What's hot (20)

開發環境建置
開發環境建置開發環境建置
開發環境建置
 
啟動 Laravel 與環境設定
啟動 Laravel 與環境設定啟動 Laravel 與環境設定
啟動 Laravel 與環境設定
 
Eloquent ORM
Eloquent ORMEloquent ORM
Eloquent ORM
 
開發環境建置
開發環境建置開發環境建置
開發環境建置
 
View 與 Blade 樣板引擎
View 與 Blade 樣板引擎View 與 Blade 樣板引擎
View 與 Blade 樣板引擎
 
COSCUP 2016 Laravel 部署工作坊 - 部署指南
COSCUP 2016 Laravel 部署工作坊 - 部署指南COSCUP 2016 Laravel 部署工作坊 - 部署指南
COSCUP 2016 Laravel 部署工作坊 - 部署指南
 
Migrations 與 Schema操作
Migrations 與 Schema操作Migrations 與 Schema操作
Migrations 與 Schema操作
 
Model 設定與 Seeding
Model 設定與 SeedingModel 設定與 Seeding
Model 設定與 Seeding
 
Laravel - 系統全攻略(續)
Laravel - 系統全攻略(續)Laravel - 系統全攻略(續)
Laravel - 系統全攻略(續)
 
開發流程與工具介紹
開發流程與工具介紹開發流程與工具介紹
開發流程與工具介紹
 
Route 路由控制
Route 路由控制Route 路由控制
Route 路由控制
 
Model 設定與 Seeding
Model 設定與 SeedingModel 設定與 Seeding
Model 設定與 Seeding
 
CRUD 綜合運用
CRUD 綜合運用CRUD 綜合運用
CRUD 綜合運用
 
Laravel - 系統全攻略
Laravel - 系統全攻略Laravel - 系統全攻略
Laravel - 系統全攻略
 
使用者認證
使用者認證使用者認證
使用者認證
 
Schema & Migration操作
Schema & Migration操作Schema & Migration操作
Schema & Migration操作
 
Package 安裝與使用
Package 安裝與使用Package 安裝與使用
Package 安裝與使用
 
HTML 語法教學
HTML 語法教學HTML 語法教學
HTML 語法教學
 
Eloquent ORM
Eloquent ORMEloquent ORM
Eloquent ORM
 
CRUD 綜合運用
CRUD 綜合運用CRUD 綜合運用
CRUD 綜合運用
 

More from Mu-Fan Teng

My experience of Ruby Education in Taiwan
My experience of Ruby Education in TaiwanMy experience of Ruby Education in Taiwan
My experience of Ruby Education in TaiwanMu-Fan Teng
 
WebSocket For Web Rubyists
WebSocket For Web RubyistsWebSocket For Web Rubyists
WebSocket For Web RubyistsMu-Fan Teng
 
20150118 學個 Sinatra 好過年
20150118 學個 Sinatra 好過年20150118 學個 Sinatra 好過年
20150118 學個 Sinatra 好過年Mu-Fan Teng
 
實踐大學教案20140329
實踐大學教案20140329實踐大學教案20140329
實踐大學教案20140329Mu-Fan Teng
 
Rails Girls Taiwan 2014 Intro
Rails Girls Taiwan 2014 IntroRails Girls Taiwan 2014 Intro
Rails Girls Taiwan 2014 IntroMu-Fan Teng
 
Introduce Ruby Taiwan@Rubykaigi2013
Introduce Ruby Taiwan@Rubykaigi2013Introduce Ruby Taiwan@Rubykaigi2013
Introduce Ruby Taiwan@Rubykaigi2013Mu-Fan Teng
 
Webconf2013-非典型貧窮網站維運經驗分享
Webconf2013-非典型貧窮網站維運經驗分享Webconf2013-非典型貧窮網站維運經驗分享
Webconf2013-非典型貧窮網站維運經驗分享Mu-Fan Teng
 
Concurrency model for mysql data processing@rubyconf.tw 2012
Concurrency model for mysql data processing@rubyconf.tw 2012Concurrency model for mysql data processing@rubyconf.tw 2012
Concurrency model for mysql data processing@rubyconf.tw 2012Mu-Fan Teng
 

More from Mu-Fan Teng (9)

My experience of Ruby Education in Taiwan
My experience of Ruby Education in TaiwanMy experience of Ruby Education in Taiwan
My experience of Ruby Education in Taiwan
 
WebSocket For Web Rubyists
WebSocket For Web RubyistsWebSocket For Web Rubyists
WebSocket For Web Rubyists
 
20150118 學個 Sinatra 好過年
20150118 學個 Sinatra 好過年20150118 學個 Sinatra 好過年
20150118 學個 Sinatra 好過年
 
實踐大學教案20140329
實踐大學教案20140329實踐大學教案20140329
實踐大學教案20140329
 
Rails Girls Taiwan 2014 Intro
Rails Girls Taiwan 2014 IntroRails Girls Taiwan 2014 Intro
Rails Girls Taiwan 2014 Intro
 
Introduce Ruby Taiwan@Rubykaigi2013
Introduce Ruby Taiwan@Rubykaigi2013Introduce Ruby Taiwan@Rubykaigi2013
Introduce Ruby Taiwan@Rubykaigi2013
 
Webconf2013-非典型貧窮網站維運經驗分享
Webconf2013-非典型貧窮網站維運經驗分享Webconf2013-非典型貧窮網站維運經驗分享
Webconf2013-非典型貧窮網站維運經驗分享
 
Concurrency model for mysql data processing@rubyconf.tw 2012
Concurrency model for mysql data processing@rubyconf.tw 2012Concurrency model for mysql data processing@rubyconf.tw 2012
Concurrency model for mysql data processing@rubyconf.tw 2012
 
Ruby on discuz
Ruby on discuzRuby on discuz
Ruby on discuz
 

Sinatra Tutorial@Rubyconf.TW2011

  • 1. 用Sinatra建置高效能 與高自訂性的系統 Mu-Fan Teng@Rubyconf.TW 2011 TOMLAN Software Studio 1 11年8月26日星期五
  • 2. About me • 鄧慕凡(Mu-Fan Teng) •a.k.a: Ryudo •http://twitter.com/ryudoawaru •Ruby developer since 2007 •Founder of Tomlan Software Studio. 2 11年8月26日星期五
  • 4. Agenda • Sinatra Introduction • Tutorial • Rails Metal • Production tips 4 11年8月26日星期五
  • 5. Why Sinatra 5 11年8月26日星期五
  • 6. Load lesser, run faster! Rails 3.1預設: 不含project本身約20個middleware 6 11年8月26日星期五
  • 7. Load lesser, run faster! Sinatra:預設不超過6個 def build(*args, &bk) builder = Rack::Builder.new builder.use Rack::MethodOverride if method_override? builder.use ShowExceptions if show_exceptions? builder.use Rack::CommonLogger if logging? builder.use Rack::Head setup_sessions builder middleware.each { |c,a,b| builder.use(c, *a, &b) } builder.run new!(*args, &bk) builder end 7 11年8月26日星期五
  • 8. Sinatra • very micro web framework(少於1600行) • pure Ruby/Rack • DSL化設計 8 11年8月26日星期五
  • 9. 完全自訂性 • 自己選擇的ORM • 自己選擇template engine • 可簡單可複雜的路由設定 9 11年8月26日星期五
  • 10. 適用場合 10 11年8月26日星期五
  • 13. Sinatra適合 • Tiny WEB App • 聊天室 • Widget • WEB API 13 11年8月26日星期五
  • 14. Tutorial開始 14 11年8月26日星期五
  • 15. Hello Sinatra! require 'rubygems' require 'sinatra' get '/' do 'Hello Sinatra!' end 15 11年8月26日星期五
  • 16. 流程 BEFORE ROUTES AFTER before get ‘/’ after before ‘/users’ post ‘/users’ after ‘/users’ put ‘/users/:id’ get ‘/users/:id’ 16 11年8月26日星期五
  • 17. Named Route Params require 'rubygems' require 'sinatra' get '/hello/:name' do # => get '/hello/Rubyconf' # params[:name] => Rubyconf "Hello #{params[:name]}!" end Sinatra中的Route就如同Rails的Action + Route, 可 透過路由表示式的設定將URI字串中符合批配樣 式的內容(冒號開頭)化為特定的params hash成員. 17 11年8月26日星期五
  • 18. Splat Param Route get '/say/*/to/*' do # /say/hello/to/world params[:splat] # => ["hello", "world"] end get '/download/*.*' do # /download/path/to/file.xml params[:splat] # => ["path/to/file", "xml"] end 在路由表示式中的*號會以陣列成員的形式集 中到特定的params[:splat]中. 18 11年8月26日星期五
  • 19. Route matching with Regular Expressions get %r{/posts/name-([w]+)} do # => get /posts/name-abc, params[:captures][0] = 'abc' "Hello, #{params[:captures].first}!" end get %r{/posts/([w]+)} do |pid| # => put match content to block param(s) # => matches 「([w]+)」 to 「pid」 end 路由表示式也接受Regular Expression並可將match 內容化為特定的params[:captures]陣列成員, 也可直 接設定為Block區域變數 19 11年8月26日星期五
  • 20. Route with block paramaters get '/thread/:tid' do |tid| # => tid == params[:tid] end get '/pictures/*.*' do |filename, ext| # => filename == first * # => ext == second * # => GET '/pictures/abc.gif' then filename = "abc" and ext = "gif" "filename = #{filename}, ext = #{ext}" end get %r{/posts/([w]+)} do |pid| # => put match content to block param(s) # => matches 「([w]+)」 to 「pid」 end 以上所介紹的路由表示式都可以將匹配的內容 指派到區塊的區域變數中 20 11年8月26日星期五
  • 21. Conditional route get '/foo', :agent => /MSIEs(d.d+)/ do "You're using IE version #{params[:agent][0]}" # => IE特製版 end get '/', :host_name => /^admin./ do "Admin Area, Access denied!" end 也可以用user_agent或host_name來做路由啟發 的條件; 注意的是agent可以是字串或正規表示 式, hostname只能是正規表示式. 21 11年8月26日星期五
  • 22. Conditions(2) get '/', :provides => 'html' do erb :index end get '/', :provides => ['rss', 'atom', 'xml'] do builder :feed end provides的條件是看accept header而非path 22 11年8月26日星期五
  • 23. RESTful Routes get '/posts' do # => Get some posts end get '/posts/:id' do # => Get 1 post end create '/posts' do # => create a post end put '/posts/:id' # => Update a post end delete '/posts/:id' # => Destroy a post end 23 11年8月26日星期五
  • 24. Route Return Values 1. HTTP Status Code 2. Headers 3. Response Body(Responds to #each) 24 11年8月26日星期五
  • 25. Http Streaming class FlvStream #http://goo.gl/B8BdU .... def each ... end end class Application < Sinatra::Base # Catch everyting and serve as stream get %r((.*)) do |path| path = File.expand_path(STORAGE_PATH + path) status(401) && return unless path =~ Regexp.new(STORAGE_PATH) flv = FlvStream.new(path, params[:start].to_i) throw :response, [200, {'Content-Type' => 'application/x-flv', "Content-Length" => flv.length.to_s}, flv] end end 由於只要有each這個method就可以當做Response Body, 因此在App Server支援的前提下就可以做出Http Streaming 25 11年8月26日星期五
  • 26. Template Engines • 支援數不清的樣板引擎(erb/haml/sass/ coffeescript/erubis/builder/markdown...) • 支援inline template • 透過Tilt可自訂樣板引擎 26 11年8月26日星期五
  • 27. Template Eengines get '/' do haml :index, :format => :html4 # overridden #render '/views/index.haml' end get '/posts/:id.html' do @post = Post.find(params[:id]) erb "posts/show.html".to_sym, :layout => 'layouts/app.html'.to_sym #render '/views/posts/show.html.erb' with #layout '/views/layouts/app.html.erb' end get '/application.css' do sass :application #render '/views/application.sass' end 所有的view名稱都必需是symbol, 不可以是String 27 11年8月26日星期五
  • 28. Compass Integration set :app_file, __FILE__ set :root, File.dirname(__FILE__) set :views, "views" set :public, 'static' configure do Compass.add_project_configuration(File.join(Sinatra::Application.root, 'config', 'compass.config')) end get '/stylesheets/:name.css' do content_type 'text/css', :charset => 'utf-8' sass(:"stylesheets/#{params[:name]}", Compass.sass_engine_options ) end 28 11年8月26日星期五
  • 29. Inline Templates get '/' do erb :"root" end template :root do <<"EOB" <p>Hello Sinatra!</p> EOB end 29 11年8月26日星期五
  • 30. Before filters before '/rooms/:room_id' do puts "Before route「/rooms/*」 only" @room = Room.find(params[:room_id]) end before do puts "Before all routes" end get '/' do ... end get '/rooms/:room_id' do puts "object variable 「@room」 is accessiable now!" "You are in room #{@room.name}" end 30 11年8月26日星期五
  • 31. Before filters • 和路由使用相同表示式 • 沒有Rails的「prepend_before_filter」 • 先載入的先執行 31 11年8月26日星期五
  • 32. Before filter order before '/rooms/:room_id' do # 先執行 # Before route「/rooms/*」 only @room = Room.find(params[:room_id]) end before do # 後執行 # Before all routes end get '/' do ... end get '/rooms/:room_id' do # object variable 「@room」 is accessiable now! "You are in room #{@room.name}" end 32 11年8月26日星期五
  • 33. Session enable :sessions # equal to 「use Rack::Session::Cookie」 post '/sessions' do @current_user = User.auth(params[:account], params[:passwd]) session[:uid] = @current_user.id if @current_user end delete '/sessions' do session[:uid] = nil redirect '/' end 33 11年8月26日星期五
  • 34. Cookies get '/' do response.set_cookie('foo', :value => 'BAR') response.set_cookie("thing", { :value => "thing2", :domain => 'localhost', :path => '/', :expires => Time.today, :secure => true, :httponly => true }) end get '/readcookies' do cookies['thing'] # => thing2 end 34 11年8月26日星期五
  • 35. Helpers helpers do def member2json(id) Member.find(id).attributes.to_json end end get '/members/:id.json' do member2json(params[:id]) end 35 11年8月26日星期五
  • 36. Helpers Helpers can use in: 1. filters 2. routes 3. templates 36 11年8月26日星期五
  • 37. Halt & Pass • Halt • 相當於控制結構中的break, 阻斷後續執 行強制回應. • Pass • 相當於控制結構中的next. 37 11年8月26日星期五
  • 38. Halt Example helpers do def auth unless session[:uid] halt 404, 'You have not logged in yet.' end end end before '/myprofile' do auth end get '/myprofile' do #如果session[:uid]為nil,則此route不會執行 end 38 11年8月26日星期五
  • 39. Pass Example get '/checkout' do pass if @current_member.vip? #一般客結帳處理 erb "normal_checkout".to_sym end get '/checkout' do #VIP專用結帳處理 erb 'vip_checkout'.to_sym end 39 11年8月26日星期五
  • 40. body,status,headers get '/' do status 200 headers "Allow" => "BREW, POST, GET, PROPFIND, WHEN" body 'Hello' # => 設定body body "#{body} Sinatra" # => 加料body end 40 11年8月26日星期五
  • 41. url and redirect get '/foo' do redirect to('/bar') end url(別名to)可以生成包含了baseuri的url; redirect則 同其名可進行http重定向並可附加訊息或狀態碼. 41 11年8月26日星期五
  • 42. send_file get '/attachments/:file' do send_file File.join('/var/www/attachments/', params[:file]) #可用選項有 # filename:檔名 # last_modified:顧名思義, 預設值為該檔案的mtime # type:內容類型,如果沒有會從文件擴展名猜測。 # disposition:Content-Disposition, 可能的包括: nil (默認), :attachment (下載附件) 和 :inline(瀏覽器內顯示) # length:Content-Length,預設為檔案size end 另⼀一個helper: attachment等於send_file的disposition 為:attachement的狀況. 42 11年8月26日星期五
  • 43. request物件 # 在 http://example.com/example 上運行的應用 get '/foo' do request.body # 被客戶端設定的請求體(見下) request.scheme # "http" request.script_name # "/example", 即為SUB-URI request.path_info # "/foo" request.port # 80 request.request_method # "GET" request.query_string # "" 查詢參數 request.content_length # request.body的長度 request.media_type # request.body的媒體類型 end 43 11年8月26日星期五
  • 44. settings #以下三行都是同一件事 set :abc, 123 set :abc => 123 settings.abc = 123 ###可用區塊###### set(:foo){|val| puts(val) } get '/' do settings.foo('Sinatra') #will puts "Sinatra" "setting abc = #{settings.abc}" end Sinatra提供了多種方式讓你在Class Scope和Request Scope都能取用與設定資料或區塊, 其中有⼀一些預設 的settings是有關系統運作與設定的. 44 11年8月26日星期五
  • 45. 重要的setting • public(public) • 指定public目錄的位置 • views(views) • 指定template/views目錄位置 • static(true) • 是否由Sinatra處理靜態檔案, 設為false交給WEB伺服器會增強效能 • lock(false) • 設定false開啟thread模式(單⼀一行程⼀一次處理多個requests) • methid_override(視情況而定) • 開始「_method」參數以使用get/post以外的http method • show_exceptions(預設值與environment有關) • 是否像rails⼀一樣顯示error stack 45 11年8月26日星期五
  • 46. settings的特別用途 set(:probability) { |value| condition { rand <= value } } get '/win_a_car', :probability => 0.1 do "You won!" end get '/win_a_car' do "Sorry, you lost." end condition是⼀一個Sinatra內建的method,可以視傳 入區塊的執行結果為true或false決定視否執行 該route或pass掉. 46 11年8月26日星期五
  • 47. configure do Configure Block # 直接設定值 set :option, 'value' # 一次設定多個值 set :a => 1, :b => 2 # 等於設定該值為true enable :option # 同上 disable :option # 可用區塊 set(:css_dir) { File.join(views, 'css') } end configure :production do # 可針對環境(RACK_ENV)做設定 LOGGER.level = Logger::WARN end get '/' do settings.a? # => true settings.a # => 1 end 類似Rails的environment.rb, 在行程啟動時執行⼀一次. 47 11年8月26日星期五
  • 48. 錯誤處理 1. not_found 2. 特定error class 3. http status code 4. 對應所有錯誤 48 11年8月26日星期五
  • 49. error block error do #透過env['sinatra.error'] 可取得錯誤物件 'Sorry there was a nasty error - ' + env['sinatra.error'].name end error 處理區塊在任何route或filter拋出錯誤的時候 會被調用。 錯誤物件可以通過sinatra.error的env hash項目取得, 可以使用任何在錯誤發生前的filter或 route中定義的instance variable及環境變數等 49 11年8月26日星期五
  • 50. 自定義error block error MyCustomError do 'So what happened was...' + env['sinatra.error'].message #輸出為:「 So what happened was... something bad」 end get '/' do raise MyCustomError, 'something bad' end 如同Ruby的rescue區塊, error處理⼀一樣可以針對 error class做定義;也可以在執行期故意啟發特定 error class的錯誤並附加訊息. 50 11年8月26日星期五
  • 51. 自定義error block error 403 do 'Access forbidden' end get '/secret' do 403 end error 400..510 do 'Boom' end 針對特定的HTTP CODE設定錯誤處理區塊, 可以是 代碼範圍 51 11年8月26日星期五
  • 52. not_found block not_found do 'This is nowhere to be found' end not_found區塊等於 error 404區塊 52 11年8月26日星期五
  • 53. Rack Middleware require 'rubygems' require 'sinatra' use Rack::Auth::Basic, "Restricted Area" do |username, password| [username, password] == ['admin', '12345'] end get '/' do "You are authorized!" end 和Rails⼀一樣, Sinatra也是基於Rack的middleware, 所以 可以使用其它的Rack middleware. 53 11年8月26日星期五
  • 54. 模組化 require 'rubygems' require 'sinatra/base' #不可以require "sinatra" 以避免頂層Object Class被汙染 class MyApp < Sinatra::Base set :sessions, true set :foo, 'bar' get '/' do 'Hello world!' end end 為了建構可重用的組件,需要將你的Sinatra應用程式 模組化以將程式化為⼀一個獨立的Rack Middleware. 54 11年8月26日星期五
  • 55. Multiple App in 1 process #config.ru require 'rubygems' require 'sinatra/base' class App1 < Sinatra::Base get '/' do 'I am App1' end end class App2 < Sinatra::Base get '/' do 'I am App2' end end map '/' do run App1 end map '/app2' do run App2 end 利用Rack::Builder可將不同的Rack App掛在不同的uri 下面. 55 11年8月26日星期五
  • 56. 何時需要模組化 • 特定的Rack App Server(Passenger/Heroku等) • 將你的Sinatra App當做⼀一個Middleware而非終 點(endpoint), 例如: 1. ⼀一次掛載多個Sinatra App在同⼀一個rackup 2. 在Rails內掛載Sinatra App 56 11年8月26日星期五
  • 57. Rails Metal #routes.rb TestMixin::Application.routes.draw do devise_for :users mount ApiApp, :at => '/api'# => 掛載 ApiApp在/api 下 root :to => "welcome#index" end #lib/api_app.rb class ApiApp < Sinatra::Base get '/users/:id.json' do User.find(params[:id]).attributes.to_json end end 57 11年8月26日星期五
  • 58. 限制 • 「可以」使用Rails的model • 「不可以」使用Rails的helper/controller • 「可能可以」使用Rails的views, 但極不建 議 • not_found的錯誤是「由Rails端」處理 • 「不可以」直接使用綁定Rails(Railties)的 組件 58 11年8月26日星期五
  • 59. Devise Mix-in #config/routes.rb TestMixin::Application.routes.draw do devise_for :users mount ApiApp, :at => '/api'# => 掛載 ApiApp在/api 下 end #lib/api_app.rb class ApiApp < Sinatra::Base get '/users/:id.json' do #等效 devise的 authenticate_user! request.env['warden'].authenticate!(:scope => 'user') User.find(params[:id]).attributes.to_json end end 由於Devise是建構在Warden(Rack Middleware)之上, 雖然不能直接使用Devise的認證helper, 但可以用 warden的方式來處理認證的問題. 59 11年8月26日星期五
  • 60. Scopes and Binding • Sinatra的變數定義域分成兩種 1. Application/Class Scope 2. Request/Instance Scope 60 11年8月26日星期五
  • 61. Scopes-範例 class MyApp < Sinatra::Base # => Application/Class Scope configure do # => Application/Class Scope set :foo, 100 end self.foo # => 100 helpers do # => Application/Class Scope def foo # => Request scope for all routes end end get '/users/:id' do # => Request scope for "/users/:id" only settings.foo # => 100 end get '/' do # => Request scope for '/' only end end Request scope可透過settings helper取得在 Application scope定義的設定值 61 11年8月26日星期五
  • 62. Application/Class scope 1. 應用程式的Class Body 2. helpers/configure的區塊內 3. 傳遞給set的區塊 62 11年8月26日星期五
  • 63. Request/Instance scope 1. session/request物件只在這裡有效 2. 作用於: 2.1.routes區塊 2.2.helper methods 2.3.view/templates 2.4.before/after filters 2.5.error block 2.6. 傳給settings的區塊中的condition區塊 63 11年8月26日星期五
  • 64. 實體變數的定義範圍 class MyApp < Sinatra::Base before do # => Request scope for all routes @varall = 100 end before '/posts/:id' do @post = Post.find(params[:id]) end get '/posts/:id' do # => Request scope for 「/posts/:id」 @post.nil? # => false @varall # => 100 settings.get('/foo'){ # => Request scope for 「/foo」 only @varall # => 100 @post.nil? # => true } end get '/' do @varall # => 100 @post # => nil end end 就算是在route block中定義的另⼀一個route block, ⼀一樣 不能共用實體變數, 在before filter中定義的實體變數 會傳到下⼀一個符合條件的before filter與route block. 64 11年8月26日星期五
  • 65. 存在Class Body中的Request Scope #####sinatra/base.rb## module Sinatra class Base class << self def host_name(pattern) condition { pattern === request.host } end end end end ##等同於自行定義############# set(:host_name){|pattern| condition { pattern === request.host }} ###################### get '/', :host_name => /^admin./ do "Admin Area, Access denied!" end 傳遞給condition method的區塊內的scope是Request Scope, 所以可以使用request物件 65 11年8月26日星期五
  • 66. Production Tips 1. ORM 2. Useful Extensions 3. Paginators 4. boot.rb 66 11年8月26日星期五
  • 67. ActiveRecord require 'rubygems' require 'sinatra' require 'active_record' #先建立連線 ActiveRecord::Base.establish_connection( :adapter => 'sqlite3', :database => 'sinatra_application.sqlite3.db' ) #require或宣告class class Post < ActiveRecord::Base end get '/' do @posts = Post.all() erb :index end 67 11年8月26日星期五
  • 68. Mongoid require 'rubygems' require 'sinatra' require 'mongoid' Mongoid.configure do |config| config.master = Mongo::Connection.new.db("godfather") end class User include Mongoid::Document include Mongoid::Timestamps end get '/users/:id.json' do User.find(params[:id]).to_json end 68 11年8月26日星期五
  • 69. Sinatra More • MarkupPlugin • 設定form以及html tag的helper等 • RenderPlugin • content_for/yield等 • WardenPlugin • 綁定單⼀一Class做登入處理 • MailerPlugin • 顧名思義, 但不是使用ActionMailer • RoutingPlugin • 做出有namespace以及restful的路由 • code generator • 建立project框架 69 11年8月26日星期五
  • 70. WillPaginate • 3.0後版本已直接以extension型式支援Sinatra • 2.3版本需要手動改寫renderer • 由於Sinatra不像Rails有固定的url形式約束, 必要時還是要自己改寫renderer 70 11年8月26日星期五
  • 71. Kaminari • Model Paginate功能可正常使用 • View Helpers的部份無法使用 • 需依照ORM require正確的組件 71 11年8月26日星期五
  • 72. boot.rb require 'bundler' Bundler.setup Bundler.require class FreeChat3 < Sinatra::Base configure do #settings set :sessions, true #Middlewares use Rack::Flash #Sinatra Extensions register SinatraMore::MarkupPlugin #DB Connections ActiveRecord::Base.establish_connection(DB_CONFIG[RACK_ENV]) Mongoid.load! File.join(ROOT_DIR, '/config/mongoid.yml') #load Model/Controller/helper/Libs Dir.glob(File.join(ROOT_DIR, '/lib/*.rb')).each{|f| require f } Dir.glob(File.join(ROOT_DIR, '/app/models/*.rb')).each{|f| require f } Dir.glob(File.join(ROOT_DIR, '/app/helpers/*.rb')).each{|f| require f } Dir.glob(File.join(ROOT_DIR, '/app/controllers/*.rb')).each{|f| load f } end helpers do include ApplicationHelper include ActionView::Helpers::TextHelper end end 72 11年8月26日星期五
  • 73. Q&A 73 11年8月26日星期五