Your SlideShare is downloading. ×
0
用Sinatra建置高效能              與高自訂性的系統                Mu-Fan Teng@Rubyconf.TW 2011                   TOMLAN Software Studio  ...
About me       •      鄧慕凡(Mu-Fan Teng)              •a.k.a: Ryudo              •http://twitter.com/ryudoawaru             ...
311年8月26日星期五
Agenda              • Sinatra Introduction              • Tutorial              • Rails Metal              • Production ti...
Why Sinatra                   511年8月26日星期五
Load lesser, run faster!       Rails 3.1預設: 不含project本身約20個middleware                         611年8月26日星期五
Load lesser, run faster!                         Sinatra:預設不超過6個               def build(*args, &bk)                 build...
Sinatra              • very micro web framework(少於1600行)              • pure Ruby/Rack              • DSL化設計              ...
完全自訂性              • 自己選擇的ORM              • 自己選擇template engine              • 可簡單可複雜的路由設定                             91...
適用場合               1011年8月26日星期五
1111年8月26日星期五
1211年8月26日星期五
Sinatra適合              • Tiny WEB App               • 聊天室               • Widget              • WEB API                   ...
Tutorial開始                  1411年8月26日星期五
Hello Sinatra!       require rubygems       require sinatra       get / do         Hello Sinatra!       end               ...
流程       BEFORE              ROUTES            AFTER      before            get ‘/’            after      before ‘/users’ ...
Named Route Params              require rubygems              require sinatra              get /hello/:name do            ...
Splat Param Route          get /say/*/to/* do            # /say/hello/to/world            params[:splat] # => ["hello", "w...
Route matching with                Regular Expressions              get %r{/posts/name-([w]+)} do                # => get ...
Route with block                     paramaters     get /thread/:tid do |tid|       # => tid == params[:tid]     end     g...
Conditional route              get /foo, :agent => /MSIEs(d.d+)/ do                "Youre using IE version #{params[:agent...
Conditions(2)               get /, :provides => html do                 erb :index               end               get /, ...
RESTful Routes              get /posts do                # => Get some posts              end              get /posts/:id ...
Route Return Values         1. HTTP Status Code         2. Headers         3. Response Body(Responds to #each)            ...
Http Streaming              class FlvStream    #http://goo.gl/B8BdU                  ....                  def each ... en...
Template Engines              • 支援數不清的樣板引擎(erb/haml/sass/               coffeescript/erubis/builder/markdown...)          ...
Template Eengines        get / do          haml :index, :format => :html4 # overridden        #render /views/index.haml   ...
Compass Integration        set   :app_file, __FILE__        set   :root, File.dirname(__FILE__)        set   :views, "view...
Inline Templates              get / do                erb :"root"              end              template :root do         ...
Before filters              before /rooms/:room_id do                puts "Before route「/rooms/*」 only"                @roo...
Before filters              • 和路由使用相同表示式              • 沒有Rails的「prepend_before_filter」              • 先載入的先執行              ...
Before filter order               before /rooms/:room_id do                 # 先執行                 # Before route「/rooms/*」 ...
Session              enable :sessions # equal to 「use Rack::Session::Cookie」              post /sessions do               ...
Cookies              get / do                response.set_cookie(foo, :value => BAR)                response.set_cookie("t...
Helpers              helpers do                def member2json(id)                  Member.find(id).attributes.to_json    ...
Helpers              Helpers can use in:         1. filters         2. routes         3. templates                         ...
Halt & Pass              • Halt               • 相當於控制結構中的break, 阻斷後續執                行強制回應.              • Pass           ...
Halt Example              helpers do                def auth                  unless session[:uid]                    halt...
Pass Example              get /checkout do                pass if @current_member.vip?                #一般客結帳處理            ...
body,status,headers              get / do                status 200                headers "Allow"   => "BREW, POST, GET, ...
url and redirect                get /foo do                  redirect to(/bar)                end        url(別名to)可以生成包含了b...
send_file        get /attachments/:file do          send_file File.join(/var/www/attachments/, params[:file])          #可用選...
request物件         # 在 http://example.com/example 上運行的應用         get /foo do           request.body              # 被客戶端設定的請...
settings        #以下三行都是同一件事        set :abc, 123        set :abc => 123        settings.abc = 123        ###可用區塊######    ...
重要的setting              •   public(public)                  •   指定public目錄的位置              •   views(views)               ...
settings的特別用途          set(:probability) { |value| condition { rand <= value } }          get /win_a_car, :probability => ...
configure do                     Configure Block          # 直接設定值          set :option, value          # 一次設定多個值          s...
錯誤處理              1. not_found              2. 特定error class              3. http status code              4. 對應所有錯誤      ...
error block        error do          #透過env[sinatra.error] 可取得錯誤物件          Sorry there was a nasty error -  + env[sinatra...
自定義error block        error MyCustomError do          So what happened was... + env[sinatra.error].message          #輸出為:「...
自定義error block        error 403 do          Access forbidden        end        get /secret do          403        end     ...
not_found block        not_found do          This is nowhere to be found        end        not_found區塊等於 error 404區塊      ...
Rack Middleware        require rubygems        require sinatra        use Rack::Auth::Basic, "Restricted Area" do |usernam...
模組化        require rubygems        require sinatra/base        #不可以require "sinatra" 以避免頂層Object Class被汙染        class MyA...
Multiple App in 1 process        #config.ru        require rubygems        require sinatra/base        class App1 < Sinatr...
何時需要模組化        • 特定的Rack App Server(Passenger/Heroku等)        • 將你的Sinatra App當做⼀一個Middleware而非終              點(endpoint),...
Rails Metal        #routes.rb        TestMixin::Application.routes.draw do          devise_for :users          mount ApiAp...
限制              • 「可以」使用Rails的model              • 「不可以」使用Rails的helper/controller              • 「可能可以」使用Rails的views, 但極不建...
Devise Mix-in        #config/routes.rb        TestMixin::Application.routes.draw do          devise_for :users          mo...
Scopes and Binding              • Sinatra的變數定義域分成兩種               1. Application/Class Scope               2. Request/Inst...
Scopes-範例        class MyApp < Sinatra::Base          # => Application/Class Scope          configure do            # => A...
Application/Class scope              1. 應用程式的Class Body              2. helpers/configure的區塊內              3. 傳遞給set的區塊    ...
Request/Instance scope              1. session/request物件只在這裡有效              2. 作用於:               2.1.routes區塊            ...
實體變數的定義範圍        class MyApp < Sinatra::Base          before do            # => Request scope for all routes            @v...
存在Class Body中的Request Scope        #####sinatra/base.rb##        module Sinatra          class Base            class << se...
Production Tips              1. ORM              2. Useful Extensions              3. Paginators              4. boot.rb  ...
ActiveRecord        require rubygems        require sinatra        require active_record        #先建立連線        ActiveRecord...
Mongoid        require rubygems        require sinatra        require mongoid        Mongoid.configure do |config|        ...
Sinatra More              •   MarkupPlugin                  •   設定form以及html tag的helper等              •   RenderPlugin    ...
WillPaginate         • 3.0後版本已直接以extension型式支援Sinatra         • 2.3版本需要手動改寫renderer         • 由於Sinatra不像Rails有固定的url形式約束,...
Kaminari         • Model Paginate功能可正常使用         • View Helpers的部份無法使用         • 需依照ORM require正確的組件                      ...
boot.rb        require bundler        Bundler.setup        Bundler.require        class FreeChat3 < Sinatra::Base         ...
Q&A               7311年8月26日星期五
Upcoming SlideShare
Loading in...5
×

Sinatra Tutorial@Rubyconf.TW2011

2,554

Published on

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

Published in: Technology
0 Comments
13 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
2,554
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
60
Comments
0
Likes
13
Embeds 0
No embeds

No notes for slide

Transcript of "Sinatra Tutorial@Rubyconf.TW2011"

  1. 1. 用Sinatra建置高效能 與高自訂性的系統 Mu-Fan Teng@Rubyconf.TW 2011 TOMLAN Software Studio 111年8月26日星期五
  2. 2. About me • 鄧慕凡(Mu-Fan Teng) •a.k.a: Ryudo •http://twitter.com/ryudoawaru •Ruby developer since 2007 •Founder of Tomlan Software Studio. 211年8月26日星期五
  3. 3. 311年8月26日星期五
  4. 4. Agenda • Sinatra Introduction • Tutorial • Rails Metal • Production tips 411年8月26日星期五
  5. 5. Why Sinatra 511年8月26日星期五
  6. 6. Load lesser, run faster! Rails 3.1預設: 不含project本身約20個middleware 611年8月26日星期五
  7. 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 711年8月26日星期五
  8. 8. Sinatra • very micro web framework(少於1600行) • pure Ruby/Rack • DSL化設計 811年8月26日星期五
  9. 9. 完全自訂性 • 自己選擇的ORM • 自己選擇template engine • 可簡單可複雜的路由設定 911年8月26日星期五
  10. 10. 適用場合 1011年8月26日星期五
  11. 11. 1111年8月26日星期五
  12. 12. 1211年8月26日星期五
  13. 13. Sinatra適合 • Tiny WEB App • 聊天室 • Widget • WEB API 1311年8月26日星期五
  14. 14. Tutorial開始 1411年8月26日星期五
  15. 15. Hello Sinatra! require rubygems require sinatra get / do Hello Sinatra! end 1511年8月26日星期五
  16. 16. 流程 BEFORE ROUTES AFTER before get ‘/’ after before ‘/users’ post ‘/users’ after ‘/users’ put ‘/users/:id’ get ‘/users/:id’ 1611年8月26日星期五
  17. 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成員. 1711年8月26日星期五
  18. 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]中. 1811年8月26日星期五
  19. 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區域變數 1911年8月26日星期五
  20. 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 以上所介紹的路由表示式都可以將匹配的內容 指派到區塊的區域變數中 2011年8月26日星期五
  21. 21. Conditional route get /foo, :agent => /MSIEs(d.d+)/ do "Youre using IE version #{params[:agent][0]}" # => IE特製版 end get /, :host_name => /^admin./ do "Admin Area, Access denied!" end 也可以用user_agent或host_name來做路由啟發 的條件; 注意的是agent可以是字串或正規表示 式, hostname只能是正規表示式. 2111年8月26日星期五
  22. 22. Conditions(2) get /, :provides => html do erb :index end get /, :provides => [rss, atom, xml] do builder :feed end provides的條件是看accept header而非path 2211年8月26日星期五
  23. 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 2311年8月26日星期五
  24. 24. Route Return Values 1. HTTP Status Code 2. Headers 3. Response Body(Responds to #each) 2411年8月26日星期五
  25. 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 2511年8月26日星期五
  26. 26. Template Engines • 支援數不清的樣板引擎(erb/haml/sass/ coffeescript/erubis/builder/markdown...) • 支援inline template • 透過Tilt可自訂樣板引擎 2611年8月26日星期五
  27. 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 2711年8月26日星期五
  28. 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 2811年8月26日星期五
  29. 29. Inline Templates get / do erb :"root" end template :root do <<"EOB" <p>Hello Sinatra!</p> EOB end 2911年8月26日星期五
  30. 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 3011年8月26日星期五
  31. 31. Before filters • 和路由使用相同表示式 • 沒有Rails的「prepend_before_filter」 • 先載入的先執行 3111年8月26日星期五
  32. 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 3211年8月26日星期五
  33. 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 3311年8月26日星期五
  34. 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 3411年8月26日星期五
  35. 35. Helpers helpers do def member2json(id) Member.find(id).attributes.to_json end end get /members/:id.json do member2json(params[:id]) end 3511年8月26日星期五
  36. 36. Helpers Helpers can use in: 1. filters 2. routes 3. templates 3611年8月26日星期五
  37. 37. Halt & Pass • Halt • 相當於控制結構中的break, 阻斷後續執 行強制回應. • Pass • 相當於控制結構中的next. 3711年8月26日星期五
  38. 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 3811年8月26日星期五
  39. 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 3911年8月26日星期五
  40. 40. body,status,headers get / do status 200 headers "Allow" => "BREW, POST, GET, PROPFIND, WHEN" body Hello # => 設定body body "#{body} Sinatra" # => 加料body end 4011年8月26日星期五
  41. 41. url and redirect get /foo do redirect to(/bar) end url(別名to)可以生成包含了baseuri的url; redirect則 同其名可進行http重定向並可附加訊息或狀態碼. 4111年8月26日星期五
  42. 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的狀況. 4211年8月26日星期五
  43. 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 4311年8月26日星期五
  44. 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是有關系統運作與設定的. 4411年8月26日星期五
  45. 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 4511年8月26日星期五
  46. 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掉. 4611年8月26日星期五
  47. 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, 在行程啟動時執行⼀一次. 4711年8月26日星期五
  48. 48. 錯誤處理 1. not_found 2. 特定error class 3. http status code 4. 對應所有錯誤 4811年8月26日星期五
  49. 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及環境變數等 4911年8月26日星期五
  50. 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的錯誤並附加訊息. 5011年8月26日星期五
  51. 51. 自定義error block error 403 do Access forbidden end get /secret do 403 end error 400..510 do Boom end 針對特定的HTTP CODE設定錯誤處理區塊, 可以是 代碼範圍 5111年8月26日星期五
  52. 52. not_found block not_found do This is nowhere to be found end not_found區塊等於 error 404區塊 5211年8月26日星期五
  53. 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. 5311年8月26日星期五
  54. 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. 5411年8月26日星期五
  55. 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 下面. 5511年8月26日星期五
  56. 56. 何時需要模組化 • 特定的Rack App Server(Passenger/Heroku等) • 將你的Sinatra App當做⼀一個Middleware而非終 點(endpoint), 例如: 1. ⼀一次掛載多個Sinatra App在同⼀一個rackup 2. 在Rails內掛載Sinatra App 5611年8月26日星期五
  57. 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 5711年8月26日星期五
  58. 58. 限制 • 「可以」使用Rails的model • 「不可以」使用Rails的helper/controller • 「可能可以」使用Rails的views, 但極不建 議 • not_found的錯誤是「由Rails端」處理 • 「不可以」直接使用綁定Rails(Railties)的 組件 5811年8月26日星期五
  59. 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的方式來處理認證的問題. 5911年8月26日星期五
  60. 60. Scopes and Binding • Sinatra的變數定義域分成兩種 1. Application/Class Scope 2. Request/Instance Scope 6011年8月26日星期五
  61. 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定義的設定值 6111年8月26日星期五
  62. 62. Application/Class scope 1. 應用程式的Class Body 2. helpers/configure的區塊內 3. 傳遞給set的區塊 6211年8月26日星期五
  63. 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區塊 6311年8月26日星期五
  64. 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. 6411年8月26日星期五
  65. 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物件 6511年8月26日星期五
  66. 66. Production Tips 1. ORM 2. Useful Extensions 3. Paginators 4. boot.rb 6611年8月26日星期五
  67. 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 6711年8月26日星期五
  68. 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 6811年8月26日星期五
  69. 69. Sinatra More • MarkupPlugin • 設定form以及html tag的helper等 • RenderPlugin • content_for/yield等 • WardenPlugin • 綁定單⼀一Class做登入處理 • MailerPlugin • 顧名思義, 但不是使用ActionMailer • RoutingPlugin • 做出有namespace以及restful的路由 • code generator • 建立project框架 6911年8月26日星期五
  70. 70. WillPaginate • 3.0後版本已直接以extension型式支援Sinatra • 2.3版本需要手動改寫renderer • 由於Sinatra不像Rails有固定的url形式約束, 必要時還是要自己改寫renderer 7011年8月26日星期五
  71. 71. Kaminari • Model Paginate功能可正常使用 • View Helpers的部份無法使用 • 需依照ORM require正確的組件 7111年8月26日星期五
  72. 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 7211年8月26日星期五
  73. 73. Q&A 7311年8月26日星期五
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×