問題
Railsで日本語URLをリンクで使っている場合、たまにデコードできないパラメータを渡されて、ActionController::BadRequest
が発生することがある。(userAgent = msnbotのときに多い?)
Controllerのbefore_action
等で対処しようとしても、フレームワークの内部でエラーが起きるので、そこまで処理がやってこない。
対処方法
ActionDispatch::Routing::RouteSet::Dispatcher
用のモンキーパッチを当てる。
以下のモンキーパッチの例ではデコードに失敗した文字列に空文字をセットしている。(sjisやeucでデコードしても正常な文字列として回復できなかったため)
# config/initializers/active_dispatch_fix.rb
module ActionDispatch::Routing::RouteSet::DispatcherFix
def call env
params = env[ActionDispatch::Routing::RouteSet::PARAMETERS_KEY]
params.each do |key, value|
unless value.valid_encoding?
Rails.logger.info "[INFO] Clear invalid value for #{key}"
params[key] = ''
end
end
super
end
end
ActionDispatch::Routing::RouteSet::Dispatcher.send :prepend, ActionDispatch::Routing::RouteSet::DispatcherFix
以下はRSpecでテストする場合のサンプルコード。
# spec/requests/examples_spec.rb
require 'spec_helper'
describe 'Examples' do
context 'with invalid parameter' do
let(:invalid_path) { '/examples/%E3%E2%80%9A%BD%E3%C6%92' }
before do
allow(Rails.logger).to receive(:info)
end
it 'handles as RecordNotFound and writes log' do
expect(Rails.logger).to receive(:info).with('[INFO] Clear invalid value for some_key').once
expect{ get invalid_path }.to raise_error(ActiveRecord::RecordNotFound)
end
end
end
参考文献
- ベースにしたロジックはこちら。
- https://gist.github.com/morr/9399606
- RSpecを読み書きするのが苦手な方はこちらの電子書籍を!
- Everyday Rails - RSpecによるRailsテスト入門
Special thanks to
- @tkawa -- 上記gistのURLを教えてくれました。ありがとうございました。