73
Sinatra建置高效能 與高自訂性的系統 Mu-Fan [email protected] 2011 TOMLAN Software Studio 1 11年8月26日星期五

Sinatra [email protected]

Embed Size (px)

DESCRIPTION

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

Citation preview

Page 1: Sinatra Tutorial@Rubyconf.TW2011

用Sinatra建置高效能與高自訂性的系統

Mu-Fan [email protected] 2011TOMLAN Software Studio

1

11年8月26日星期五

Page 2: Sinatra Tutorial@Rubyconf.TW2011

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日星期五

Page 3: Sinatra Tutorial@Rubyconf.TW2011

3

11年8月26日星期五

Page 4: Sinatra Tutorial@Rubyconf.TW2011

Agenda

• Sinatra Introduction

• Tutorial

• Rails Metal

• Production tips

4

11年8月26日星期五

Page 5: Sinatra Tutorial@Rubyconf.TW2011

Why Sinatra

5

11年8月26日星期五

Page 6: Sinatra Tutorial@Rubyconf.TW2011

Load lesser, run faster!Rails 3.1預設: 不含project本身約20個middleware

6

11年8月26日星期五

Page 7: Sinatra Tutorial@Rubyconf.TW2011

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日星期五

Page 8: Sinatra Tutorial@Rubyconf.TW2011

Sinatra

• very micro web framework(少於1600行)

• pure Ruby/Rack

• DSL化設計

8

11年8月26日星期五

Page 9: Sinatra Tutorial@Rubyconf.TW2011

完全自訂性• 自己選擇的ORM

• 自己選擇template engine

• 可簡單可複雜的路由設定

9

11年8月26日星期五

Page 10: Sinatra Tutorial@Rubyconf.TW2011

適用場合

10

11年8月26日星期五

Page 11: Sinatra Tutorial@Rubyconf.TW2011

11

11年8月26日星期五

Page 12: Sinatra Tutorial@Rubyconf.TW2011

12

11年8月26日星期五

Page 13: Sinatra Tutorial@Rubyconf.TW2011

Sinatra適合• Tiny WEB App

• 聊天室

• Widget

• WEB API

13

11年8月26日星期五

Page 14: Sinatra Tutorial@Rubyconf.TW2011

Tutorial開始

14

11年8月26日星期五

Page 15: Sinatra Tutorial@Rubyconf.TW2011

Hello Sinatra!require 'rubygems'require 'sinatra'get '/' do 'Hello Sinatra!'end

15

11年8月26日星期五

Page 16: Sinatra Tutorial@Rubyconf.TW2011

流程

get ‘/’ROUTES

post ‘/users’

put ‘/users/:id’

get ‘/users/:id’

beforeBEFORE

before ‘/users’

after

AFTER

after ‘/users’

16

11年8月26日星期五

Page 17: Sinatra Tutorial@Rubyconf.TW2011

Named Route Params

Sinatra中的Route就如同Rails的Action + Route, 可透過路由表示式的設定將URI字串中符合批配樣式的內容(冒號開頭)化為特定的params hash成員.

17

require 'rubygems'require 'sinatra'

get '/hello/:name' do # => get '/hello/Rubyconf' # params[:name] => Rubyconf "Hello #{params[:name]}!"end

11年8月26日星期五

Page 18: Sinatra Tutorial@Rubyconf.TW2011

Splat Param Routeget '/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日星期五

Page 19: Sinatra Tutorial@Rubyconf.TW2011

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日星期五

Page 20: Sinatra Tutorial@Rubyconf.TW2011

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日星期五

Page 21: Sinatra Tutorial@Rubyconf.TW2011

Conditional route

get '/foo', :agent => /MSIE\s(\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日星期五

Page 22: Sinatra Tutorial@Rubyconf.TW2011

Conditions(2)get '/', :provides => 'html' do erb :indexend

get '/', :provides => ['rss', 'atom', 'xml'] do builder :feedend

provides的條件是看accept header而非path

22

11年8月26日星期五

Page 23: Sinatra Tutorial@Rubyconf.TW2011

RESTful Routesget '/posts' do # => Get some postsend

get '/posts/:id' do # => Get 1 postend

create '/posts' do # => create a postend

put '/posts/:id' # => Update a postend

delete '/posts/:id' # => Destroy a postend

23

11年8月26日星期五

Page 24: Sinatra Tutorial@Rubyconf.TW2011

Route Return Values

1. HTTP Status Code

2. Headers

3. Response Body(Responds to #each)

24

11年8月26日星期五

Page 25: Sinatra Tutorial@Rubyconf.TW2011

Http Streamingclass FlvStream #http://goo.gl/B8BdU

....def each ... end

endclass 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] endend

由於只要有each這個method就可以當做Response Body, 因此在App Server支援的前提下就可以做出Http Streaming

25

11年8月26日星期五

Page 26: Sinatra Tutorial@Rubyconf.TW2011

Template Engines

• 支援數不清的樣板引擎(erb/haml/sass/coffeescript/erubis/builder/markdown...)

• 支援inline template

• 透過Tilt可自訂樣板引擎

26

11年8月26日星期五

Page 27: Sinatra Tutorial@Rubyconf.TW2011

Template Eenginesget '/' 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'endget '/application.css' do sass :application#render '/views/application.sass'end

所有的view名稱都必需是symbol,不可以是String

27

11年8月26日星期五

Page 28: Sinatra Tutorial@Rubyconf.TW2011

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'))endget '/stylesheets/:name.css' do content_type 'text/css', :charset => 'utf-8' sass(:"stylesheets/#{params[:name]}", Compass.sass_engine_options )end

28

11年8月26日星期五

Page 29: Sinatra Tutorial@Rubyconf.TW2011

Inline Templatesget '/' do erb :"root"end

template :root do<<"EOB"<p>Hello Sinatra!</p>

EOBend

29

11年8月26日星期五

Page 30: Sinatra Tutorial@Rubyconf.TW2011

Before filtersbefore '/rooms/:room_id' do puts "Before route「/rooms/*」 only" @room = Room.find(params[:room_id])endbefore do puts "Before all routes"endget '/' do ...endget '/rooms/:room_id' do puts "object variable 「@room」 is accessiable now!" "You are in room #{@room.name}"end

30

11年8月26日星期五

Page 31: Sinatra Tutorial@Rubyconf.TW2011

Before filters

• 和路由使用相同表示式• 沒有Rails的「prepend_before_filter」

• 先載入的先執行

31

11年8月26日星期五

Page 32: Sinatra Tutorial@Rubyconf.TW2011

Before filter orderbefore '/rooms/:room_id' do # 先執行 # Before route「/rooms/*」 only @room = Room.find(params[:room_id])endbefore do # 後執行 # Before all routesendget '/' do ...endget '/rooms/:room_id' do # object variable 「@room」 is accessiable now! "You are in room #{@room.name}"end

32

11年8月26日星期五

Page 33: Sinatra Tutorial@Rubyconf.TW2011

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_userenddelete '/sessions' do session[:uid] = nil redirect '/'end

33

11年8月26日星期五

Page 34: Sinatra Tutorial@Rubyconf.TW2011

Cookiesget '/' 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'] # => thing2end

34

11年8月26日星期五

Page 35: Sinatra Tutorial@Rubyconf.TW2011

Helpers

helpers do def member2json(id) Member.find(id).attributes.to_json endendget '/members/:id.json' do member2json(params[:id])end

35

11年8月26日星期五

Page 36: Sinatra Tutorial@Rubyconf.TW2011

HelpersHelpers can use in:

1. filters

2. routes

3. templates

36

11年8月26日星期五

Page 37: Sinatra Tutorial@Rubyconf.TW2011

Halt & Pass

• Halt

• 相當於控制結構中的break, 阻斷後續執行強制回應.

• Pass

• 相當於控制結構中的next.

37

11年8月26日星期五

Page 38: Sinatra Tutorial@Rubyconf.TW2011

Halt Examplehelpers do def auth unless session[:uid] halt 404, 'You have not logged in yet.' end endend

before '/myprofile' do authend

get '/myprofile' do #如果session[:uid]為nil,則此route不會執行end

38

11年8月26日星期五

Page 39: Sinatra Tutorial@Rubyconf.TW2011

Pass Exampleget '/checkout' do pass if @current_member.vip? #一般客結帳處理 erb "normal_checkout".to_symendget '/checkout' do #VIP專用結帳處理 erb 'vip_checkout'.to_symend

39

11年8月26日星期五

Page 40: Sinatra Tutorial@Rubyconf.TW2011

body,status,headers

get '/' do status 200 headers "Allow" => "BREW, POST, GET, PROPFIND, WHEN" body 'Hello' # => 設定body body "#{body} Sinatra" # => 加料bodyend

40

11年8月26日星期五

Page 41: Sinatra Tutorial@Rubyconf.TW2011

url and redirect

get '/foo' do redirect to('/bar')end

url(別名to)可以生成包含了baseuri的url; redirect則同其名可進行http重定向並可附加訊息或狀態碼.

41

11年8月26日星期五

Page 42: Sinatra Tutorial@Rubyconf.TW2011

send_fileget '/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,預設為檔案sizeend

另⼀一個helper: attachment等於send_file的disposition為:attachement的狀況.

42

11年8月26日星期五

Page 43: Sinatra Tutorial@Rubyconf.TW2011

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日星期五

Page 44: Sinatra Tutorial@Rubyconf.TW2011

settings

#以下三行都是同一件事set :abc, 123set :abc => 123settings.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日星期五

Page 45: Sinatra Tutorial@Rubyconf.TW2011

重要的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日星期五

Page 46: Sinatra Tutorial@Rubyconf.TW2011

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日星期五

Page 47: Sinatra Tutorial@Rubyconf.TW2011

Configure Blockconfigure do # 直接設定值 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::WARNend

get '/' do settings.a? # => true settings.a # => 1end

類似Rails的environment.rb, 在行程啟動時執行⼀一次.47

11年8月26日星期五

Page 48: Sinatra Tutorial@Rubyconf.TW2011

錯誤處理1. not_found

2. 特定error class

3. http status code

4. 對應所有錯誤

48

11年8月26日星期五

Page 49: Sinatra Tutorial@Rubyconf.TW2011

error block

error do #透過env['sinatra.error'] 可取得錯誤物件 'Sorry there was a nasty error - ' + env['sinatra.error'].nameend

error 處理區塊在任何route或filter拋出錯誤的時候會被調用。 錯誤物件可以通過sinatra.error的env hash項目取得, 可以使用任何在錯誤發生前的filter或route中定義的instance variable及環境變數等

49

11年8月26日星期五

Page 50: Sinatra Tutorial@Rubyconf.TW2011

自定義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日星期五

Page 51: Sinatra Tutorial@Rubyconf.TW2011

自定義error block

error 403 do 'Access forbidden'end

get '/secret' do 403enderror 400..510 do 'Boom'end

針對特定的HTTP CODE設定錯誤處理區塊, 可以是代碼範圍

51

11年8月26日星期五

Page 52: Sinatra Tutorial@Rubyconf.TW2011

not_found block

not_found do 'This is nowhere to be found'end

not_found區塊等於 error 404區塊

52

11年8月26日星期五

Page 53: Sinatra Tutorial@Rubyconf.TW2011

Rack Middleware

和Rails⼀一樣, Sinatra也是基於Rack的middleware, 所以可以使用其它的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

53

11年8月26日星期五

Page 54: Sinatra Tutorial@Rubyconf.TW2011

模組化

為了建構可重用的組件,需要將你的Sinatra應用程式模組化以將程式化為⼀一個獨立的Rack Middleware.

require 'rubygems'require 'sinatra/base'#不可以require "sinatra" 以避免頂層Object Class被汙染class MyApp < Sinatra::Base set :sessions, true set :foo, 'bar' get '/' do 'Hello world!' endend

54

11年8月26日星期五

Page 55: Sinatra Tutorial@Rubyconf.TW2011

Multiple App in 1 process

利用Rack::Builder可將不同的Rack App掛在不同的uri下面.

#config.rurequire 'rubygems'require 'sinatra/base'class App1 < Sinatra::Base get '/' do 'I am App1' endendclass App2 < Sinatra::Base get '/' do 'I am App2' endendmap '/' do run App1endmap '/app2' do run App2end

55

11年8月26日星期五

Page 56: Sinatra Tutorial@Rubyconf.TW2011

何時需要模組化• 特定的Rack App Server(Passenger/Heroku等)

• 將你的Sinatra App當做⼀一個Middleware而非終點(endpoint), 例如:1. ⼀一次掛載多個Sinatra App在同⼀一個rackup

2. 在Rails內掛載Sinatra App

56

11年8月26日星期五

Page 57: Sinatra Tutorial@Rubyconf.TW2011

Rails Metal

#routes.rbTestMixin::Application.routes.draw do devise_for :users mount ApiApp, :at => '/api'# => 掛載 ApiApp在/api 下 root :to => "welcome#index"end#lib/api_app.rbclass ApiApp < Sinatra::Base get '/users/:id.json' do User.find(params[:id]).attributes.to_json endend

57

11年8月26日星期五

Page 58: Sinatra Tutorial@Rubyconf.TW2011

限制• 「可以」使用Rails的model

• 「不可以」使用Rails的helper/controller

• 「可能可以」使用Rails的views, 但極不建議

• not_found的錯誤是「由Rails端」處理

• 「不可以」直接使用綁定Rails(Railties)的組件

58

11年8月26日星期五

Page 59: Sinatra Tutorial@Rubyconf.TW2011

Devise Mix-in

#config/routes.rbTestMixin::Application.routes.draw do devise_for :users mount ApiApp, :at => '/api'# => 掛載 ApiApp在/api 下end#lib/api_app.rbclass ApiApp < Sinatra::Base get '/users/:id.json' do #等效 devise的 authenticate_user! request.env['warden'].authenticate!(:scope => 'user') User.find(params[:id]).attributes.to_json endend

由於Devise是建構在Warden(Rack Middleware)之上,雖然不能直接使用Devise的認證helper, 但可以用warden的方式來處理認證的問題.

59

11年8月26日星期五

Page 60: Sinatra Tutorial@Rubyconf.TW2011

Scopes and Binding

• Sinatra的變數定義域分成兩種1. Application/Class Scope

2. Request/Instance Scope

60

11年8月26日星期五

Page 61: Sinatra Tutorial@Rubyconf.TW2011

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 endend

Request scope可透過settings helper取得在Application scope定義的設定值

61

11年8月26日星期五

Page 62: Sinatra Tutorial@Rubyconf.TW2011

Application/Class scope1. 應用程式的Class Body

2. helpers/configure的區塊內3. 傳遞給set的區塊

62

11年8月26日星期五

Page 63: Sinatra Tutorial@Rubyconf.TW2011

Request/Instance scope1. 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日星期五

Page 64: Sinatra Tutorial@Rubyconf.TW2011

實體變數的定義範圍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 endend

就算是在route block中定義的另⼀一個route block, ⼀一樣不能共用實體變數, 在before filter中定義的實體變數會傳到下⼀一個符合條件的before filter與route block.

64

11年8月26日星期五

Page 65: Sinatra Tutorial@Rubyconf.TW2011

存在Class Body中的Request Scope

#####sinatra/base.rb##module Sinatra class Base class << self def host_name(pattern) condition { pattern === request.host } end end endend##等同於自行定義#############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日星期五

Page 66: Sinatra Tutorial@Rubyconf.TW2011

Production Tips1. ORM

2. Useful Extensions

3. Paginators

4. boot.rb

66

11年8月26日星期五

Page 67: Sinatra Tutorial@Rubyconf.TW2011

ActiveRecord

require 'rubygems'require 'sinatra'require 'active_record'

#先建立連線ActiveRecord::Base.establish_connection( :adapter => 'sqlite3', :database => 'sinatra_application.sqlite3.db')#require或宣告classclass Post < ActiveRecord::Baseend

get '/' do @posts = Post.all() erb :index end

67

11年8月26日星期五

Page 68: Sinatra Tutorial@Rubyconf.TW2011

Mongoid

require 'rubygems'require 'sinatra'require 'mongoid'Mongoid.configure do |config| config.master = Mongo::Connection.new.db("godfather")endclass User include Mongoid::Document include Mongoid::Timestampsendget '/users/:id.json' do User.find(params[:id]).to_jsonend

68

11年8月26日星期五

Page 69: Sinatra Tutorial@Rubyconf.TW2011

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日星期五

Page 70: Sinatra Tutorial@Rubyconf.TW2011

WillPaginate

• 3.0後版本已直接以extension型式支援Sinatra

• 2.3版本需要手動改寫renderer

• 由於Sinatra不像Rails有固定的url形式約束, 必要時還是要自己改寫renderer

70

11年8月26日星期五

Page 71: Sinatra Tutorial@Rubyconf.TW2011

Kaminari

• Model Paginate功能可正常使用

• View Helpers的部份無法使用

• 需依照ORM require正確的組件

71

11年8月26日星期五

Page 72: Sinatra Tutorial@Rubyconf.TW2011

boot.rbrequire 'bundler'Bundler.setupBundler.requireclass 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日星期五

Page 73: Sinatra Tutorial@Rubyconf.TW2011

Q&A

73

11年8月26日星期五