iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 3
0
Modern Web

向 Rails 致敬!30天寫一個網頁框架,再拿來做一個 Todo List系列 第 3

[DAY 3] 復刻 Rails - Rails app or Rack app?

昨天我們已經學會如何建立一個 gem,今天就直接開始進入主題吧!

認識 Rack

Rack 是一個應用程式能讓你的框架與 server 進行溝通,可以說是大部分用 ruby 開發的 framework,都是以他為基礎,所以也會有人稱呼 Rails 其實就是一個 Rack app,關於 Rack 的官方說明如下

Rack is a gem to interface your framework to a Ruby application server such as Mongrel, Thin, Lighttpd, Passenger, WEBrick or Unicorn. An application server is a special type of web server that runs server applications, often in Ruby. In a real production environment you would run a web server like Apache or NGinX in front of the application servers.

看說明其實不是那麼好懂(其實是英文不好),只知道他介於 web framework(例如: Rails) 和 web server(例如: Nginx)之間,搭配圖片說明可能比較清楚 Rack 在幹嘛

圖片來源

看完圖片後,對於現在的我們來說,只要先記住兩件事情就好

  1. 雖然說我們在復刻 Rails,但其實我們真正在做的是一個 Rack app,一切框架基礎都是基於 Rack 所打造
  2. 由 Rack 處理所有的 request/response

做一個 Rack App 來練習手感

一樣跟昨天一天,認識一個新的東西,先從基本的範例開始學起,我們先建立一個 my_rack 的目錄,並且在底下建立一個 config.ru 檔案

# my_rack/config.ru

run proc {
  [200, {'Content-Type' => 'text/html'},
 ["Hola, El mundo!"]]
}

這段程式碼表示當瀏覽器每次執行 request 時,Rack 就會執行 run proc {},並且 response 會回傳一個 http status code 為 200, 同時也會告訴瀏覽器 HTTP header 和 body

接著開啟 web server rackup -p 3001

$ rackup -p 3001

Puma starting in single mode...
* Version 4.3.5 (ruby 2.6.6-p146), codename: Mysterious Traveller
* Min threads: 0, max threads: 16
* Environment: development
* Listening on tcp://127.0.0.1:3001
* Listening on tcp://[::1]:3001

打開瀏覽器,連到 http://127.0.0.1:3001/,這時候就會在瀏覽器上看到以下文字

Hola, El mundo!

Mavericks 的誕生

現在我們已經知道怎麼做出一個 gem,也知道 Rails 是基於 Rack 建立的 web framework 接下來就正式開始來建立一個 framework,吧!

$ mavericks/bundle gem mavericks

框架的名字看自己的喜好而定,但如果要上傳到 rubygems.org,記得先檢查名字是不是被人用過,這裡我替這個框架命名為 Mavericks

接著跟之前一樣,把 gemspec 裡面的 TODO 都先填寫完,然後在 gemspec 的最底下加上

# mavericks/mavericks.gemspec

  spec.bindir        = "exe"
  spec.executables   = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
  spec.require_paths = ["lib"]
  # 加上底下這行
  spec.add_runtime_dependency "rack"

代表 Mavericks 這個框架會用到 Rack,如果你想加上測試工具(ex: Rspec),也可以加上

gem.add_development_dependency "rspec"

接著執行 build,然後將 gem 安裝在電腦上

gem build mavericks.gemspec
gem install mavericks-0.1.0.gem

建立一個 Todo List 專案

在第一天的時候有提到,我們會用我們所建立的框架,來做一個 Todo list 的網站,今天就順手一起建立吧!當然現在還沒辦法像 Rails 一樣,執行 rails new app_name 就很快生成專案,所以現在辛苦一點,先徒手建立,這裡我們把專案名稱取名為 just_do,做就對了

$ mkdir just_do
$ cd just_do

# 建立 config 和 app 資料夾
$ mkdir config
$ mkdir app

# 建立 Gemfile
$ touch Gemfile

在 Gemfile 裡面加上你剛剛建立好的 Mavericks

# just_do/Gemfile

source 'https://rubygems.org'
gem 'mavericks'

然後就跟 Rails 一樣,加上 gem 以後記得先 bundle,bundle 完就會生成出 Gemfile.lock 檔案

$ bundle install

接著繼續在專案目錄底下建立 config.ru,填上 response 的內容

# just_do/config.ru

run proc {
[200, {'Content-Type' => 'text/html'},
 ["Just do !!"]]
}

最後啟動 server

$ rackup -p 3001

打開瀏覽器連到 http://127.0.0.1:3001/,沒意外的話應該會在畫面上看到這串文字

Just do !!

雖然可以正常運作,但現在的狀況有點像是,由 just_do 這個專案在處理 request,我們應該要讓 Mavericks 來處理才對(不然安裝他幹嘛),所以要稍微修改一下程式碼,讓我們再回到 Mavericks

# mavericks/lib/mavericks.rb
require "mavericks/version"

module Mavericks
  class Error < StandardError; end

  class Application
    def call(env)
      [200, {'Content-Type' => 'text/html'},
       ["I use mavericks, just do !!"]]
    end
  end
end

然後一樣重新 build 新的 gem 並且安裝

gem build mavericks.gemspec
gem install mavericks-0.1.0.gem

注意要把舊的 mavericks-0.1.0.gem,並且執行 git add .,不然在 build 的過程中會出錯

接著再回到 just_do 的專案,建立一個 config/application.rb 檔案

# just_do/config/application.rb

require 'mavericks'

module JustDo
  class Application < Mavericks::Application
  end
end

將 Mavericks require 進來以後,讓 class Applicaion 做繼承,最後修改 config.ru 這個檔案,把原本的程式碼換成底下這段

# just_do/config.ru 

require_relative 'config/application'
run JustDo::Application.new

這裡利用 Rack 的 run 來執行 Application 的物件,只要這個物件帶有 call 這個 method,Rack 就會去執行裡面那段程式碼,接下來跟剛剛一樣啟動伺服器查看瀏覽器畫面

I use mavericks, just do !!

回頭看看 Rails

如果你現在建立一個 Rails 專案,你會發現 Rails 也是在做一樣的事情

# ./config/application.rb

module Cart
  class Application < Rails::Application
  (略)
  end
end
# ./config.ru

require_relative 'config/environment'

run Rails.application

其他開發者說...

比較我們的 Mavericks 和 Rails 的專案,同樣的都繼承了 Application,接著在 config.ru 執行一個 Rack Application,到這裡有沒有開始覺得,好像有這麼一點,我們真的在做框架的感覺?

讀者:「X啦,我們根本沒辦法建立自己的內容呀,這是什麼網頁框架」(按檢舉)

先...先等等...,才第三天而已

現在我們運用這兩天學到的知識,建立起一個簡單的 framework 名叫 Mavericks,Mavericks 裡面用了 Rack 來幫助我們接收 request,也可以做出基本回應,但很明顯的我們還缺少很多東西,尤其是整個 MVC 的架構,明天我們將會從 controller 開始建立


上一篇
[DAY 2] 復刻 Rails - 從建立第一個 gem 開始
下一篇
[DAY 4] 復刻 Rails - 從 Controller 開始
系列文
向 Rails 致敬!30天寫一個網頁框架,再拿來做一個 Todo List30

尚未有邦友留言

立即登入留言