任何以 Ruby 寫的框架,都可以透過 Rack 中介軟體來修改他的運作方式
Rack 是以一層層的方式建構你的框架及應用程式
用 Rack 做出來的應用程式,會有 config.ru 檔,是一種 RackUp 檔案
Rack 使用 call() 來呼叫 Endpoints
就像呼叫 Proc 一樣
# sample_dir/config.ru
run proc {
[200, {'Content-Type' => 'text/html'}, ["Hello, world!"]]
}
這段程式碼會回傳 HTTP 狀態、header 跟 body
使用 rackup -p 3001 或 bundle exec rackup -p 3001 跑
會開啟 3001 的 port
然後你會看到 Hello, world!
你可以用 call 方法去指定一個 endpoint 物件
endpoint
endpoint 會告訴 API 該走哪個路徑,請它去找相對應的 controller 及 action
# sample_dir/config.ru
obj = Object.new
def obj.call(*args)
[200, {'Content-Type' => 'text/html'}, ["Hello, world!"]]
end
run obj
接下來,我們來看看 Rack 該怎麼運作
# sample_dir/config.ru
INNER_LAYER = proc { "world!" }
OUTER_LAYER = proc {
inner_content = INNER_LAYER.call
[
200,
{'Content-Type' => 'text/html'},
["Hello," + inner_content]
]
}
run OUTER_LAYER
內層只返回一個 world
外層把內層包起來,然後把 Hello 印出來
這是 Rack 的運作方式
每一層修改過後
內層返回一個結果
Rack 並不知道該怎麼找下一層
要找下一層就必須要寫一個可以重複使用的程式碼
相反的, Rack 會傳送每一層當作下一層初始化參數
我們要用 use 來做些設定
# sample_dir/config.ru
use Rack::Auth::Basic, "app" do |_, pass|
'secret' == pass
end
run proc {
[200, {'Content-Type' => 'text/html'}, ["Hello, world!"]]
}
拿到一個 username 以及 password
呼叫任何你想要的 user 資訊
你需要兩層的 Rack app
當我們使用 use 時,我們要跟他說要產生什麼 class 以及 傳什麼參數進去
現在我們在 config.ru 設定一下 middleware class
# sample_dir/config.ru
class Canadianize
def initialize(app, arg = "")
@app = app
@arg = arg
end
def call(env)
status, headers, content = @app.call(env)
content[0] += @arg + ", eh?"
[ status, headers, content ]
end
end
use Canadianize, ", simple"
run proc {
[200, {'Content-Type' => 'text/html'}, ["Hello world"]]
}
因為傳送了 simple 參數給 Canadianize 的初始化
所以最後會顯示在畫面上的是 Hello world , simple
這個 block 傳送給 Rack::Auth::Basic 裡的 initialize 方法
就像參數被傳進 Canadianize 中
你可以依照需求傳參數數量進去
但是 initialize() 的參數需要跟 use() 的參數一樣
# best_quotes/config.ru
require "./config/application"
run BestQuotes::Application.new
BestQuotes::Application 有 call 方法
所以你可以用 run 來呼叫他們
最後回傳的結果會顯示在瀏覽器上