Rack上のRails

このガイドでは、RackとRailsの統合と、その他のRackコンポーネントとのインターフェースについて説明します。

このガイドを読むことで、次の事が学べるはずです。

  • メタル(頑丈な?)・Railsアプリケーションの作り方について
  • RailsアプリケーションでのRackミドルウェアの使用方法について
  • Action Packの内部ミドルウェアスタックについて
  • カスタムミドルウェアスタックの定義方法について

1. Rackの紹介

Rackは、最小限のモジューラーと適合インターフェースを、RubyでのWebアプリケーションの開発のために提供します。 HTTPリクエストとレスポンスを、可能な限りシンプルな方法でラッピングすることで、 Webサーバ、Webフレームワーク、とソフトウェア(ミドルウェアと呼ばれる)間で単一のメソッドで呼べるように統一されたAPIにします。

Rackの詳細な説明については、このガイドでは行いません。 Rackの基本的な知識が無いのであれば、このガイドの「リソース」セクションを確認する必要があります。

2. Rails on Rack

2.1 RailsアプリケーションのRackオブジェクト

ApplicationName::Applicationは、Railsの主要なRackアプリケーションオブジェクトです。 Rackに準拠したWebサーバは、Railsアプリケーションへサービスを提供するApplicationName::Applicationオブジェクトを使用する必要があります。 Rails.applicationは、同じアプリケーションオブジェクトを参照します。

2.2 rails server

rails serverは、Rack::Serverオブジェクトを作成し、Webサーバーを開始する基本的なジョブを行います。

下記はrails serverRack::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を使用するには、 Railsアプリケーションのルートディレクトリのconfig.ru内に下記のように配置します。

# Rails.root/config.ru
require ::File.expand_path('../config/environment',  __FILE__)

use Rack::Debugger
use Rack::ContentLength
run Rails.application

次にサーバーを起動します。

$ rackup config.ru

その他のrackupオプションを確認するには下記のようにします。

$ rackup --help

3. Acton Dispatcher ミドルウェアスタック

Action Dispatcherの内部コンポーネントの多くは、Rackミドルウェアとして実装されています。 Rails::ApplicationActionDispatch::MiddlewareStackを使用して、 内部と外部の様々なミドルウェアを完全なRailsのRackアプリケーションの形にして結合します。

ActionDispatch::MiddlewareStackは、RailsとしてのRack::Builderと同等のものですが、 より柔軟で、よりRailsが必要とする機能を満たす構築をしてくれます。

3.1 ミドルウェアスタックの検査

Railsには、ミドルウェアスタックの検査をするための手軽なrake taskが用意されています。

$ rake middleware

新しくRailsアプリケーションを生成したばかりであれば、下記のように出力されるはずです。

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::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 MyApp::Application.routes

この各ミドルウェアの用途は、このガイドの「内部ミドルウェア」セクションで説明します。

3.2 ミドルウェアスタックの設定

Railsはシンプルな設定インターフェースであるconfig.middlewareを提供します。 これはapplication.rb、または環境固有の設定ファイルであるenviroments/(環境名).rbを通して、 ミドルウェア内のミドルウェアの追加、削除、修正を行います。

3.2.1 ミドルウェアの追加

下記のメソッドのいずれかを使用して、ミドルウェアスタックに新しいミドルウェアを追加することが出来ます。

config.middleware.use(new_middleware, args)
ミドルウェアスタックの1番下に、新しいミドルウェアを追加します。
config.middleware.insert_before(existing_middleware, new_middleware, args)
新しいミドルウェアを、指定した既存のミドルウェアの前に追加します。
config.middleware.insert_after(existing_middleware, new_middleware, args)
新しいミドルウェアを、指定した既存のミドルウェアの後に追加します。
# config/application.rb

# Rack::BounceFaviconを1番下に追加
config.middleware.use Rack::BounceFavicon

# Lifo::Cacheを{ page_cache: false }の引数付きで、
# ActiveRecord::QueryCacheの後ろに追加し、
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 列挙型(Enumerable)としてのミドルウェアスタック

ミドルウェアスタックは、通常の列挙型(Enumerable)のように振る舞います。 列挙型のメソッドを使用して、スタックの操作や問い合わせを行うことが可能です。 ミドルウェアスタックには、[]unshiftdeleteなどの一部のArrayメソッドも実装されています。 このセクションで説明したメソッドは、単なる便利メソッドに過ぎません。

下記の行をアプリケーションの設定に追加してください。

# config/application.rb
config.middleware.delete "Rack::Lock"

ここでミドルウェアスタックの検証を行った場合、 Rack::Lockが、この一部として含まれていない事に無いことに気づくでしょう。

$ rake middleware
(in /Users/lifo/Rails/blog)
use ActionDispatch::Static
use #<ActiveSupport::Cache::Strategy::LocalCache::Middleware:0x00000001c304c8>
use Rack::Runtime
...
run Blog::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 内部ミドルウェアスタック

アクションコントローラーの機能のほとんどは、ミドルウェアとして実装されています。 下記のリストは、それらの各目的にについて説明しています。

Rack::Sendfile
サーバ固有のX-Sendfileヘッダーを設定します。 config.action_dispatch.x_sendfile_headerオプションを通して、これが設定されます。
ActionDispatch::Static
静的なアセットを提供するのに使用されます。 config.serve_static_assetsがfalseの場合、無効になります。
Rack::Lock
env["rack.multithread"]フラグをfalseに設定し、 排他制御でアプリケーションをラップします。
ActiveSupport::Cache::Strategy::LocalCache::Middleware
メモリキャッシングを使用します。 このキャッシュはスレッドセーフではありません。
Rack::Runtime
X-Runtimeヘッダーを設定し、リクエストの処理に対して掛かった時間(秒)を含めます。
Rack::MethodOverride
もし、params[:_method]を設定した場合、メソッドが上書きされることを許可します。 これは、PUT、DELETEのHTTPメソッドのタイプをサポートするミドルウェアです。
ActionDispatch::RequestId
レスポンスの一意のX-Request-Idヘッダーを利用可能にし、 ActionDispatch::Request#uuidメソッドを有効にします。
Rails::Rack::Logger
リクエストが始まっている事をログに通知を行います。 リクエストが完了すると、その全てのログはクリアされます。
ActionDispatch::ShowExceptions
アプリケーションによって返される例外をrescueし、 エンドユーザー向けのフォーマットでラップした例外アプリケーションを呼び出します。
ActionDispatch::DebugExceptions
例外のログ出力と、ローカルであればデバッグページの表示を請け負います。
ActionDispatch::RemoteIp
IPスプーフィング攻撃をチェックします。
ActionDispatch::Reloader
コールバックの準備とクリーンアップを提供し、開発中のコードの再読み込みを支援します。
ActionDispatch::Callbacks
リクエストにサービスを提供する前に、コールバックの準備をします。
ActiveRecord::ConnectionAdapters::ConnectionManagement
リクエスト環境でのrack.testがtrueに設定されていなければ、各リクエスト後にアクティブな接続をクリーンします。
ActiveRecord::QueryCache
Active Recordのクエリーキャッシュを有効にします。
ActionDispatch::Cookies
リクエストのために、Cookieを設定します。
ActionDispatch::Session::CookieStore
Cookie内でのセッション格納を請け負います。
ActionDispatch::Flash
flashキーを設定します。 config.action_controller.session_storeに値が設定されている場合のみ有効です。
ActionDispatch::ParamsParser
paramsへのリクエストから、パラメータを解析します。
ActionDispatch::Head
HEADリクエストをGETリクエストへ変換し、同じように提供します。
Rack::ConditionalGet
"Conditional GET"(条件付きGET)のサポートを追加し、もしページに変更が無ければサーバは応答しません。
Rack::ETag
文字列ボディ全てにETagヘッダーを追加します。 ETagはキャッシュの検証に使用されます。

あなたのカスタムRackスタックに、上記ミドルウェアのいずれかを使用することが可能です。

3.4 Rackビルダーの使用

下記は、Railsが提供するMiddlewareStackの代わりに、 Rack::Builderを使用するように置き換える方法になります。

既存のRailsのミドルウェアスタックをクリアします。

# config/application.rb
config.middleware.clear

config.ruファイルをRails.rootに追加します。

# config.ru
use MyOwnStackFromScratch
run Rails.application

4. リソース

4.1 Rackの学習

4.2 ミドルウェアの理解

 Back to top

© 2010 - 2017 STUDIO KINGDOM