38. Route
1. HTTP VERB
2. PATH INFO
get '/hello/:name' do
# matches "GET /hello/foo" and "GET /hello/
bar"
# params[:name] is 'foo' or 'bar'
"Hello #{params[:name]}!"
end
3. RETURN RESPONSE
39. Route Type
• Named Parameters
• Splat(Wildcard) Parameters
• Regular Expressions Parameters
• Block Parameters
40. Wildcard Params
get '/say/*/to/*' do
# matches /say/hello/to/world
params[:splat] # => ["hello", "world"]
end
41. RegExp Params
get %r{/hello/([w]+)} do
"Hello, #{params[:captures].first}!"
end
42. Block Params
get '/hello/:name' do |n|
# n stores params[:name]
"Hello #{n}!"
end
get '/download/*.*' do |path, ext|
[path, ext] # => ["path/to/file", "xml"]
end
get %r{/hello/([w]+)} do |c|
"Hello, #{c}!"
end
48. Filter
before do
@member = Member.find(session[:member_id])
end
!
after do
LOGGER.info "Request Finished!"
end
49. 和 Route ⼀一樣有 Params
before "/products/:product_id" do
@current_product =
Product.find(params[:product_id])
end
!
before //products/(d+?).*" do |product_id|
@current_product = Product.find(product_id)
end
50. 可執⾏行複數 Filter
依照載⼊入順序
before do
@member = Member.find(session[:member_id])
end
!
#GET /products/1
before "/products/:product_id" do
@product = Product.find(params[:product_id])
end
!
get "/products/:id" do
# @member / @product 都有值
end
51. Filter 參數延續傳遞問題
#GET /products/1
before "/products/:product_id" do
#params[:product_id] => 1
end
!
get "/products/:id" do
#params[:product_id] => nil
#params[:id] => 1
end
54. Error Block
not_found do
'This is nowhere to be found.'
end
error ActiveRecord::RecordNotFound do
404, erb(:not_found)
end
55. Helper
helpers do
def post_path(post)
to "/posts/#{post.id}"
end
end
56. 重要的 Helper們
• session
• cookies
• to / url
• redirect
• halt
• settings
57. Session
和 Rails 相同,名為 session 的Hash
get '/:value' do
session[:value] = params[:value]
end
58. Use Another Session Store
require "rack/session/redis"
use Rack::Session::Redis, {
:url => "redis://localhost:6379/0",
:namespace => "rack:session",
:expire_after => 600
}
59. Cookie
預設其實沒有 cookie helper,要從 request 物件取得 Hash
get '/:value' do
request.cookies['cdb_sid']
end
60. to Helper
注意相對路徑,別名url
#mount in '/'
to('/') #=> ‘/'
!
#mount in '/api/v1'
to('/') #=> '/api/v1/'
61. Redirect
等同 Rails 的 redirect_to
get '/foo' do
redirect to('/bar')
end
62. Halt
離開現有流程,停⽌止後續 Route 處理並 Render Response
before "/products/:id" do
begin
@member = Member.find(session[:member_id])
rescue ActiveRecord::RecordNotFound
halt 401, erb(:notfound)
end
end
!
delete "/products/:id" do
#halt後,將不會執⾏行
end
63. Setting Value
configure do
set :foo, 'bar'
enable :session #set :session, true
disable :logging
set(:css_dir) { File.join(views, 'css') }
end
!
get '/' do
settings.foo? # => true
settings.foo # => 'bar'
...
end
64. Configure Block
在程式啟動時執⾏行⼀一次,開啟 DB 連接或執⾏行設定
configure :development do
#Only execute when development env
enable :logging
end
!
configure do
enable :method_override
set :view, "app/views"
end
65. Variable Scope
class MyApp < Sinatra::Base
#此處為 Class Scope
set :foo, 42
foo # => 42
get '/foo' do
# 進⼊入 Request Scope
end
end
Class Scope
Instance Scope
69. 變數傳遞持久性
Named
Params
Form
Params
Instance
Variables
Request
Object
持久性僅限於
Route Block 有有有
70. Modular App Style
require 'sinatra/base'
class MyApp < Sinatra::Base
# OR Sinatra::Application
set :sessions, true
set :foo, 'bar'
get '/' do
'Hello world!'
end
end
74. Rackup File
# This file is used by Rack-based servers to
start the application.
!
require ::File.expand_path('../config/
environment', __FILE__)
run Rails.application
76. Modular App in Rackup File
#config.ru
require 'sinatra/base'
class MyApp < Sinatra::Base
# OR Sinatra::Application
set :sessions, true
set :foo, 'bar'
get '/' do
'Hello world!'
end
end
run MyApp
79. Run Multi App in 1 Rackup
require 'sinatra/base'
class App1 < Sinatra::Application
get '/' do
'app1'
end
end
class App2 < Sinatra::Application
get '/' do
'app2'
end
end
map('/app1'){run App1}
map('/app2'){run App2}
83. Mount in Rails Route
#routes.rb
Rails.application.routes.draw do
root 'hello#world'
resources :customers
mount Api::V1, at: '/api/v1'
end
#lib/api/v1.rb
class Api::V1 < Sinatra::Application
get '/' do
'API'
end
end
84. Mount Outside Rails
# This file is used by Rack-based servers to
start the application.
require ::File.expand_path('../config/
environment', __FILE__)
require ::File.expand_path('../lib/api/v1',
__FILE__)
map '/api/v1' do
run Api::V1
end
run Rails.application
90. Model Code
class Customer < ActiveRecord::Base
def self.fetch(idgt = nil)
where("customerid > ?",
idgt.to_i).limit(20).map(&:ser)
end
end
91. Rails Controller Code
class CustomersController <
ApplicationController
def index
respond_to do |f|
f.json do
render json: Customer.fetch.to_json
end
end
end
end
92. Sinatra Code
module Api
class V1 < Sinatra::Application
get '/customers.json' do
Customer.fetch.to_json
end
end
end
93. config.ru
# This file is used by Rack-based servers to
start the application.
require ::File.expand_path('../config/
environment', __FILE__)
require ::File.expand_path('../lib/api/v1',
__FILE__)
map '/ext/api/v1' do
run Api::V1
end
run Rails.application
95. URL 對應表
Rails http://localhost:3000/customers.json
Mount in Rails
Route
http://localhost:3000/api/v1/customers.json
Mount in
Rackup
http://localhost:3000/ext/api/v1/customers.json
96. 測試結果
Rails
Mount in Rails
Route
Mount in Rackup
(outside of Rails)
RPQ平均150~ 200~ 300+
111. 可以只開啟Rails或只開啟
Sinatra
#config.ru
if ENV['RUN_ONLY'] == 'rails'
run Rails.application
elsif ENV['RUN_ONLY'] == 'sinatra'
run MySinatraApp
else
map '/api/v1' do
run MySinatraApp
end
run Rails.application
end
134. 標準的 Rails 程式碼
# in app/controllers/customers_controller.rb
class CustomersController < ApplicatoController
...
def index
@customers = Customer.page(1)
end
end
# in app/views/customers/index.html.erb
<ul>
<%=render @customers%>
</ul>
# in app/views/customers/_customer.html.erb
<li><%=customer.id%>:<%=customer.name%></li>
135. 它可以產⽣生的 HTML
<ul>
<li>1:很好填</li>
<li>2:⾃自⼰己填</li>
<li>3:不想填</li>
<li>4:給你填</li>
</ul>
147. “Difference between a master and
a beginner? The master has failed
more times than the beginner has
even tried.”
⼤大師與新⼿手之間的差別,就是⼤大師失敗過的次
數,⽐比新⼿手嘗試過的次數還多