alias_method_chain と prepend を同時に同じメソッドに適用できない問題
Rails 5.0 のリリースが近づいてきてますが、Rails 5.0 から alias_method_chain
を使っていると deprecation warning が出るようになりました https://github.com/rails/rails/pull/19434 。
単純に alias_method_chain
を prepend
に書き換えればいいかと思いきや、かなりのレアケースではあるけれども、以前実際に失敗した事例の紹介です。
#!/usr/bin/env ruby require 'active_support/all' module M def foo p 'M#foo' super end end class C def foo p 'C#foo' end end class C def foo_with_modified p 'C#foo modified' foo_without_modified end alias_method_chain :foo, :modified prepend M end C.new.foo
これを実行すると
"M#foo" "C#foo modified" "C#foo"
という出力結果が得られる。予想通り。
#!/usr/bin/env ruby require 'active_support/all' module M def foo p 'M#foo' super end end class C def foo p 'C#foo' end end class C def foo_with_modified p 'C#foo modified' foo_without_modified end prepend M alias_method_chain :foo, :modified end C.new.foo
これを実行すると SystemStackError。変わったのは alias_method_chain
と prepend
の順序だけ。
言われてみればたしかにそうなるのはわかるけれども、たとえば activerecord をモンキーパッチで拡張するような gem が複数あった場合、たまたま同じメソッドに対する alias_method_chain
と prepend
が混在していると、初期化順でエラーになったりならなかったりする。