はじめに
- はじめに
- 実務でぶつかった課題
- prependで実装した内容
- 一番面白いと感じたこと: メソッドの探索順序(MRO)が変わる
- Laravel(PHP)やPythonでは何が近いか
- 同じような仕組みは他の言語にもあるか調べてみた
- 実務で使ってみて感じたこと
- どんな人におすすめか
- 参考
- まとめ
- テコテックの採用活動について
システム開発第二事業部の高山です。普段はエンジニアとして、主にRubyを使用してバックエンドの開発を行っています。
実務でRailsのログマスキングを実装し直す中で prepend を使う機会がありました。一番面白いと感じたのは、prependが単なる「機能追加の仕組み」ではなく、クラスのメソッド探索順序(Method Resolution Order、以下MRO)そのものを書き換える仕組みだったことです。呼び出し側のコードは1行も変えていないのに、実際に呼ばれるメソッドが変わる。この感覚は、他言語出身者にはあまり馴染みがないのではと思い、実務でどう使ったかとあわせて紹介します。
実務でぶつかった課題
きっかけは、Railsのログマスキングの実装方法を見直したことでした。
Railsには元々 config.filter_parameters(ActiveSupport::ParameterFilter)という、指定したキーの値をログ上で[FILTERED]に置き換える仕組みが用意されています。ただしこれには2つの制約があります。1つは、キーと値のペアを受け取って値を置き換えるだけなので既存にないキーを新しく追加することはできないこと。もう1つは、フィルタ条件がキー名ベースで、リクエストパスごとに対象を変えられないことです。
実務では「パスごとに対象キーを変えつつ、文字数という新しい情報をログに出す」という要件だったため、標準のfilter_parametersだけでは実現できず、もともとはミドルウェアで実装する予定でした。しかしミドルウェアの層で新しいログ用の項目を作ろうとすると、Railsがログ出力時に見ているのは結局request.parameters由来の値なので、新しいキーを反映させるには実際のリクエストパラメーターに値を追加するしかありません。その結果、ミドルウェアで項目を追加した分だけ、コントローラーには本来送られていないはずの項目が追加されて届いてしまうという副作用がありました。パラメーターは permit で明示的に許可したものしか使われないので機能的に壊れることはなさそうでしたが、思わぬ弊害を引き起こす可能性も考えられました。
そこで、ログ出力時の値だけをその場で加工する方針に変更することにし、Railsのリクエストログが request.filtered_parameters の戻り値を使っていることに着目しました。ここだけを狙い撃ちできれば、コントローラーやミドルウェアには一切手を入れずに済みます。この「入口を変えずに、戻り値だけ加工する」という要件と、prepend の「元の処理をsuperで包む」という性質が綺麗にはまりました。
続きを読む