このガイドはRackのミドルウェア、urlマップ、Rack::Builder
といったRackのプロトコルや概念に関する実用的な知識があることを前提にしています。
1 Rack入門
Rackは、Rubyのウェブアプリケーションに対して、最小限でモジュール化されていて、応用の効くインターフェイスを提供します。RackはHTTPリクエストとレスポンスを可能なかぎり簡単な方法でラッピングすることで、ウェブサーバー、ウェブフレームワーク、その間に位置するソフトウェア (ミドルウェアと呼ばれています) のAPIを一つのメソッド呼び出しの形にまとめます。
Rackに関する解説はこのガイドの範疇を超えてしまいます。Rackに関する基本的な知識が足らない場合、下記のリソース を参照してください。
2 RailsとRack
2.1 RackアプリケーションとしてのRailsアプリケーション
Rails.application
はRailsアプリケーションをRackアプリケーションとして実装したものです。Rackに準拠したWebサーバーで、Railsアプリケーションを提供するには、Rails.application
オブジェクトを使用する必要があります。
2.2 rails server
コマンド
rails server
コマンドはRack::Server
のオブジェクトを作成し、ウェブサーバーを起動します。
rails server
コマンドは以下のようにして、Rack::Server
のオブジェクトを作成します。
Rails::Server.new.tap do |server| require APP_PATH Dir.chdir(Rails.application.root) server.start end
Rails::Server
クラスはRack::Server
クラスを継承しており、以下のようにしてRack::Server#start
を呼び出します。
class Server < ::Rack::Server def start ... super end end
また次のようにして、ミドルウェアを読み込みます。
def middleware middlewares = [] middlewares << [Rails::Rack::Debugger] if options[:debugger] middlewares << [::Rack::ContentLength] Hash.new(middlewares) end
Rails::Rack::Debugger
は主としてdevelopment環境で役に立ちます。読み込まれたミドルウェアの役割は下表のとおりです。
ミドルウェア | 役割 |
---|---|
Rails::Rack::Debugger |
デバッガを起動する |
Rack::ContentLength |
レスポンスのバイト数を計算し、HTTP Content-Length ヘッダーをセットする |
2.3 rackup
コマンド
Railsのrails server
コマンドの代わりにrackup
コマンドを使用するときは、下記の内容をconfig.ru
に記述して、Railsアプリケーションのルートディレクトリに保存します。
# Rails.root/config.ru require ::File.expand_path('../config/environment', __FILE__) use Rails::Rack::Debugger use Rack::ContentLength run Rails.application
サーバーを起動します。
$ rackup config.ru
rackup
のオプションについて詳しく知りたいときは下記のようにします。
$ rackup --help
3 Action Dispatcherのミドルウェアスタック
Action Dispatcher内部のコンポーネントの多くは、Rackのミドルウェアとして実装されています。Rails内外の様々なミドルウェアを結合して、完全なRailsのRackアプリケーションを作るために、Rails::Application
はActionDispatch::MiddlewareStack
を使用しています。
ActionDispatch::MiddlewareStack
はRack::Builder
のRails版ですが、Railsアプリケーションの要求を満たすために、より柔軟性があり、多機能なクラスになっています。
3.1 ミドルウェアスタックを調べる
Railsにはミドルウェアスタックを調べるための便利なRakeタスクがあります。
$ bin/rake middleware
作成したばかりのRailsアプリケーションでは、以下のように出力されるはずです。
use Rack::Sendfile use ActionDispatch::Static use Rack::Lock use #<ActiveSupport::Cache::Strategy::LocalCache::Middleware:0x000000029a0838> use Rack::Runtime use Rack::MethodOverride use ActionDispatch::RequestId use Rails::Rack::Logger use ActionDispatch::ShowExceptions use ActionDispatch::DebugExceptions use ActionDispatch::RemoteIp use ActionDispatch::Reloader use ActionDispatch::Callbacks use ActiveRecord::Migration::CheckPending use ActiveRecord::ConnectionAdapters::ConnectionManagement use ActiveRecord::QueryCache use ActionDispatch::Cookies use ActionDispatch::Session::CookieStore use ActionDispatch::Flash use ActionDispatch::ParamsParser use Rack::Head use Rack::ConditionalGet use Rack::ETag run Rails.application.routes
デフォルトのミドルウェア(とその他のうちいくつか)については Internal Middlewares を参照してください。
3.2 ミドルウェアスタックを設定する
ミドルウェアスタックにミドルウェアを追加したり、削除したり、変更したりするにはapplication.rb
もしくは環境ごとのenvironments/<environment>.rb
ファイル内でconfig.middleware
をいじります。
3.2.1 ミドルウェアを追加する
次のメソッドを使用すると、ミドルウェアスタックに新しいミドルウェアを追加することができます。
config.middleware.use(new_middleware, args)
- ミドルウェアスタックの一番下に新しいミドルウェアを追加します。config.middleware.insert_before(existing_middleware, new_middleware, args)
- (第一引数で)指定されたミドルウェアの前に新しいミドルウェアを追加します。config.middleware.insert_after(existing_middleware, new_middleware, args)
- (第一引数で)指定されたミドルウェアの後に新しいミドルウェアを追加します。
# config/application.rb # Rack::BounceFaviconを一番最後に追加する config.middleware.use Rack::BounceFavicon # ActiveRecord::QueryCacheの後にLifo::Cacheを追加する # またLifo::Cacheに{ page_cache: false }を渡す config.middleware.insert_after ActiveRecord::QueryCache, Lifo::Cache, page_cache: false
3.2.2 ミドルウェアを交換する
config.middleware.swap
を使用することで、ミドルウェアスタック内のミドルウェアを交換できます。
# config/application.rb # ActionDispatch::ShowExceptionsをLifo::ShowExceptionsで置き換える config.middleware.swap ActionDispatch::ShowExceptions, Lifo::ShowExceptions
3.2.3 ミドルウェアを削除する
アプリケーションの設定に、下記のコードを追加してください。
# config/application.rb config.middleware.delete "Rack::Lock"
ミドルウェアスタックを調べると、Rack::Lock
が消えていることが分かります。
$ bin/rake middleware (in /Users/lifo/Rails/blog) use ActionDispatch::Static use #<ActiveSupport::Cache::Strategy::LocalCache::Middleware:0x00000001c304c8> use Rack::Runtime ... run Rails.application.routes
セッション関連のミドルウェアを削除したいときは次のように書きます。
# config/application.rb config.middleware.delete "ActionDispatch::Cookies" config.middleware.delete "ActionDispatch::Session::CookieStore" config.middleware.delete "ActionDispatch::Flash"
ブラウザ関連のミドルウェアを削除するには次のように書きます。
# config/application.rb config.middleware.delete "Rack::MethodOverride"
3.3 ミドルウェアスタックの内容
Action Controllerの機能の多くはミドルウェアとして実装されています。以下のリストでそれぞれの役割を説明します。
Rack::Sendfile
- X-Sendfile headerを設定します。
config.action_dispatch.x_sendfile_header
オプション経由で設定を変更できます。
ActionDispatch::Static
- 静的ファイルを配信する際に使用します。
config.serve_static_assets
をfalse
にするとオフになります。
Rack::Lock
-
env["rack.multithread"]
をfalse
に設定し、アプリケーションをMutexで包みます。
ActiveSupport::Cache::Strategy::LocalCache::Middleware
- メモリによるキャッシュを行うために使用します。このキャッシュはスレッドセーフではありません。
Rack::Runtime
- X-Runtimeヘッダーを生成します。このヘッダーにはリクエストの処理にかかった時間が秒単位で表示されます。
Rack::MethodOverride
-
params[:_method]
が存在するときに、(HTTPの)メソッドを上書きます。HTTPのPUTメソッド、DELETEメソッドを実現するためのミドルウェアです。
ActionDispatch::RequestId
- ユニークなidを生成して
X-Request-Id
ヘッダーに設定します。ActionDispatch::Request#uuid
メソッドも同一のidを利用しています。
Rails::Rack::Logger
- リクエストの処理を開始したことを、ログに書き出します。リクエストが完了すると、すべてのログをフラッシュします。
ActionDispatch::ShowExceptions
- アプリケーションが返してくる例外を捕え、例外処理用のアプリケーションを起動します。例外処理用のアプリケーションは、エンドユーザー向けに例外を整形します。
ActionDispatch::DebugExceptions
- 例外をログに残し、ローカルからのリクエストの場合は、デバッグ用のページを表示します。
ActionDispatch::RemoteIp
- IPスプーフィング攻撃をチェックします。
ActionDispatch::Reloader
- development環境でコードの再読み込みを行うために、prepareコールバックとcleanupコールバックを提供します。
ActionDispatch::Callbacks
- リクエストの処理を開始する前に、prepareコールバックを起動します(訳注: この説明は原文レベルで間違っており、現在原文の修正を行っています)。
ActiveRecord::Migration::CheckPending
- 未実行のマイグレーションがないか確認します。未実行のものがあった場合は、
ActiveRecord::PendingMigrationError
を発生さます。
ActiveRecord::ConnectionAdapters::ConnectionManagement
- リクエストを処理する度にデータベースへのコネクションをコネクションプールに返します。
env['rack.test']
がtrue
でない場合のみ返却が行われます。
ActiveRecord::QueryCache
- Active Recordのクエリキャッシュを有効にします。
ActionDispatch::Cookies
- クッキー機能を提供します。
ActionDispatch::Session::CookieStore
- クッキーにセッションを保存するようにします。
ActionDispatch::Flash
- flash機能を提供します(flashとは連続するリクエスト間で値を共有する機能です)。これは、
config.action_controller.session_store
に値が設定されている場合にのみ有効です。
ActionDispatch::ParamsParser
- リクエストからパラメータをパースして、
params
を設定します。
ActionDispatch::Head
- HEADリクエストを
GET
に変換して処理します。その上でbodyを空にしたレスポンスを返します(訳注: Rails4.0からはRack::Headを使うように変更されています)。
Rack::ConditionalGet
- "条件付き
GET
" (ConditionalGET
) 機能を提供します。"条件付きGET
"が有効になっていると、リクエストされたページに変更がないときに空のbodyを返すようになります。
Rack::ETag
- bodyが文字列のみのレスポンスに対して、ETagヘッダを追加します。 ETagはキャッシュの有効性を検証するのに使用されます。
これらのミドルウェアはいずれも、Rackのミドルウェアスタックに利用できます。