鼬~~哩賀,我是寫程式的山姆老弟,昨天跟大家一起看了 Rails 有哪些可以客製化的設定,今天來看看 RailsGuide 的 Rack 篇,了解一下 Rack 這個在 Rails 時不時就會出現的東東,夠夠~
Rack 是一個 ruby gem,負責以極簡的方式處理 HTTP requests, responses,可以完全獨立於 Rails 之外運行,
我們先試試看使用最純粹的 Rack
,也就是沒有 Rails 包裝過的 Rack
,假設我在 ~/Downloads
新增一個 config.ru
的檔案,內容如下
# ~/Downloads/config.ru
require 'rack'
class HelloWorld
def call(env)
[200, {"Content-Type" => "text/plain"}, ["Hello world, Rack!"]]
end
end
run HelloWorld.new
使用方式:$ rackup
啟動,預設是開在 9292
port
Puma starting in single mode...
* Puma version: 5.6.5 (ruby 3.0.0-p0) ("Birdie's Version")
* Min threads: 0
* Max threads: 5
* Environment: development
* PID: 88707
* Listening on http://127.0.0.1:9292
* Listening on http://[::1]:9292
Use Ctrl-C to stop
這時候去 127.0.0.1:9292
看,就可以看到我們的 Hello World
Rack
是一個把 web server(Nginx, Apache, …) 和 web framework(Rails, …) 串起來的角色
創立新的 Rails 專案的時候,Rails 就會在專案根目錄裡,自動創建 config.ru
檔案,像下面這樣,看起來是不是跟上面的 Rack Hello World 有點像,有個 run 去啟動
# config.ru
# This file is used by Rack-based servers to start the application.
require_relative "config/environment"
run Rails.application
Rails.application.load_server
當你執行 $ rails server
時,其實就是創建一個 Rails::Server
的 instance,這個 Rails::Server
其實也就是繼承 Rack::Server
,有興趣可以去 Rails 的 source code 看一下,我把最直接相關的部分截出來:
# rails/railties/lib/rails/commands/server/server_command.rb
module Rails
class Server < ::Rack::Server
...
def start(...)
trap(:INT) { exit }
create_tmp_directories
setup_dev_caching
log_to_stdout if options[:log_stdout]
super()
end
...
end
end
以上 start()
method 做的事情,其實不難理解
trap(:INT) { exit }
,抓 SYSINT
signal,當你在終端機按下 Ctrl+C 會送出 SYSINT
的訊號,如果抓到這個 signal,就 exit,跳出 rails server 的運行create_tmp_directories
,就是在 Rails 專案目錄底下的 tmp/
資料夾和底下的 pids
, cache
, sockets
的預設資料夾setup_dev_caching
,就是如果是 development 環境,就會啟動 DevCache,這根據預設設定 加上 我們在環境檔裡面的設定,來決定這個 cache 行為log_to_stdout
,就是把 log 印出到終端機,而不是寫入到檔案super()
,去執行 Rack::Server
原本該執行的啟動程序除了上面 Rails 對 Rack 的用法,Rack
在 Rails 中還扮演了其他重要的角色,就是 Rails 的各種 Middleware
我們沿用前天的專案,用 $ rails middleware
可以查看目前專案用的 middleware 有哪些
在其中可以看到很多 Rack
的身影,主要是因為 Rack
的特性,Rack
作為 middleware 可以對 request 進行前處理,處理後再交由下一層的 middleware 繼續處理,就這樣一層一層處理到最後再交由 Controller
的 action,所以 middleware 的順序是有意義的,如果有要自己開發 middleware 的話需要注意
Rake 也是一個 Ruby 的 gem,現在已經被包在 ruby 裡了,像是 C 語言的 Makefile,負責執行打包(Build)任務,但其實不限定打包,只要是 ruby 能寫的,都能用 Rake 執行
我們試著寫一個最簡單的 Rake hello world,在 ~/Downloads
新增一個叫做 Rakefile
的檔案
# ~/Downloads/Rakefile
task :hello do
puts("Hello world, Rake!")
end
然後可以在 ~/Downloads
執行 $ rake hello
你可以在一個 Rakefile 中定義很多個 tasks,也可以定義一個叫做 :default
的 task,那在執行 rake 的時候,不指定 task 的時候就會去執行 default 的任務
簡單來說,Rack
和 Rake
是兩個完全沒關係的 gem,只是字面上長得很像,同時又被 Rails
拿來用而已
今天總算是有搞懂 Rack
和 Rake
的差別,也有稍微看了下 Rails 是怎麼使用 Rack 的,才知道原來 Rack 的重要性
今天就先這樣囉,我們明天見~