はじめに
Rails でホストレベル(相対パスではなく、ドメイン名を含む絶対パスレベル)でのリダイレクトを行う場合、要件によっていくつかの実装パターンがあります。
今回はサイトリニューアルの関係でドメインが変わっており、Web アプリケーションはそのまま同じものを使用します。
また、 Rails で静的ファイルを提供する場合に使用する public
ディレクトリも含めて他のドメインへリダイレクトしたかったので、 Rack::HostRedirect を選択しました。
メジャーな他の方法はコントローラのコールバックや、routes.rbの定義で実装する方法だと思いますが、この二つでは public
ディレクトリをリダイレクトできないため、rack 層からのリダイレクトを行うこの gem を選択しました。試していませんが、Apache の mod_rewrite ばりに多機能な Rack::Rewrite あたりでも同じことができると思います。
サイトリニューアルなどでドメイン名を変更する場合、SEOの観点では相対パスをそっくり維持しドメインのみ異なる 301 Moved Permanently なリダイレクトが必要になるため、このような実装をよく行います。
実装
実装というより単に定義で終わりですが、gem を入れた後はこんな感じになります。
gem Config を使っているので、 Setting.production_old_host
に旧ドメイン、 Settings.production_host
に新ドメインを定義しています。
# config/application.rb
config.middleware.insert_before ActionDispatch::Static, Rack::HostRedirect, {
[Settings.production_old_host] => Settings.production_host
}
この gem のことを全く知らずにここだけ見ても、何をしているか分かりやすくて良いですね。
解説
キモなのは config.middleware.insert_before ActionDispatch::Static
で、この定義がないと、この gem を使っても public
ディレクトリをリダイレクトできません。
この定義が何をしているかは、Rails ガイドを読むのが一番良さそうです。
Rails ガイド | 3 Action Dispatcherのミドルウェアスタック
ちゃんと理解するには Rack とは何か? を知る必要があるのですが、Webアクセス(リクエストとレスポンス)を簡単に扱えるようにする仕組みを提供するミドルウェアといったところでしょうか。Rack はあくまで仕組みの名前で、それを実現する ミドルウェアは多数の gem で構成されています。うちの環境ではこんな感じ。
% rails middleware
use Rack::MiniProfiler
use Rack::Sendfile
use Rack::HostRedirect
use Rack::Cors
use ActionDispatch::Static
use ActionDispatch::Executor
use Rack::Runtime
use Rack::MethodOverride
use ActionDispatch::RequestId
use Rack::Timeout
use ActionDispatch::RemoteIp
use Rails::Rack::Logger
use ActionDispatch::ShowExceptions
use MetaRequest::Middlewares::Headers
use ActionDispatch::DebugExceptions
use BetterErrors::Middleware
use Rollbar::Middleware::Rails::RollbarMiddleware
use ActionDispatch::Reloader
use ActionDispatch::Callbacks
use ActiveRecord::Migration::CheckPending
use ActionDispatch::Cookies
use ActionDispatch::Session::RedisStore
use ActionDispatch::Flash
use ActionDispatch::ContentSecurityPolicy::Middleware
use Rack::Head
use Rack::ConditionalGet
use Rack::ETag
use Rack::TempfileReaper
use Warden::Manager
use Bullet::Rack
use MetaRequest::Middlewares::MetaRequestHandler
use MetaRequest::Middlewares::AppRequestHandler
run Nurses::Application.routes
入れている gem によってこの内容は変化しますが、名前でなんとなく何をやっているのか分かるものも多いですね。この中の ActionDispatch::Static
が、public
ディレクトリで静的ファイルを提供している gem です。
この ActionDispatch::Static
が先に呼び出されて実行されてしまうとリクエストを解釈してレスポンスを返すところまでやってしまうため、リダイレクト処理を挟む余地がなくなってしまいます。
そのため、config.middleware.insert_before(existing_middleware, new_middleware, args)
を使用してこの gem の前に Rack::HostRedirect
を呼び出す必要があるわけです。