Active Storageを使おうとしたら、ルーティングが干渉する事態が発生しました。
Catch allルーティングとは
Railsのルーティングはresources
などによるリソースフルなものや、get 'path/to/:id'
のようなパス形式の指定が一般的ですが、ワイルドカードを使うこともできます(Rails Guide)。
ルーティングの一部に*name
と入れると、スラッシュも含んでマッチしうるものがすべて回収されて、アクションの側ではparams[:name]
のように取得することができます。特に、get '*all'
のように書いてしまえば、あらゆるURLによるGET
リクエストがこのルーティングにマッチするようになります。このような、「あらゆるURLにマッチングするルーティング」を「Catch allルーティング」のように呼ぶこともあります。
Catch allルーティングの問題点
ルーティングは上から順に処理されていくので、Catch allルーティングが途中にあると、それ以降にあるルーティングはなんの意味も持たなくなってしまいます。自分で書いたルーティングでそんなことをする人はいないかと思いますが、ここで問題になってくるのがActive Storage(やAction Mailbox)です。
Active Storageなどが提供するルーティングは、通常の設定ではユーザーが手書きしたものよりあとに来てしまうので、Catch allをユーザーが書いているとActive Storageのルーティングは使われなくなってしまいます。
対処法
対処法としては、いくつか考えられます。
Catch allルーティングに穴を開ける
ルーティングには、constraints
としてそのルーティングを使う条件を指定することができます。ここで%r{(?!rails/).*}
のような指定を行って、rails/
以下をルーティングから一括して外す、という方法も考えられます。ただし、アドホック感が否定できないです。
ロード順を変える
Active Storageを先にロードできれば、問題は解決します。以下の設定をconfig/application.rb
に書きましょう。
config.railties_order = [ActiveStorage::Engine, :main_app, :all]
なお、[:all, :main_app]
のような設定を紹介しているものも見かけましたが、これを行うとアプリ全体の動作が大きく変化してしまいます。