Redmine プラグインで controller を load すると別のプラグインに影響がある
Module#prepend での本体のヘルパーを上書き
従来 Redmine のプラグインで本体の動作を変えたい場合は alias_method_chain を使いましょうということになっていた。
Redmine 4 系から Rails 5.x ベースとなって alias_method_chain が廃止されてからは Module#prepend を使いましょうということになった。
prepend を使えば既存の動作を上書きすることができるようになる。
# 本体のモジュール module ProjectsHelper def foo 'foo' end end # プラグインで追加するパッチ module ProjectsHelperPatch def foo super + 'bar' end end # プラグイン内でこれを実行 ProjectsHelper.prepend(ProjectsHelperPatch) # 本体のコントローラ class ProjectsController include ProjectsHelper end # ProjectsHelperPatch#foo が呼ばれる。 super は ProjectsHelper#foo を呼ぶ。 puts ProjectsController.new.foo # foobar
ロードする順番を変えてみる
順番を変えてみる。
# 本体のモジュール module ProjectsHelper def foo 'foo' end end # 本体のコントローラ(prepend よりも前にもってきた) class ProjectsController include ProjectsHelper end # プラグインで追加するパッチ module ProjectsHelperPatch def foo super + 'bar' end end # プラグイン内でこれを実行 ProjectsHelper.prepend(ProjectsHelperPatch) # ProjectsHelperPatch#foo が呼ばれず、 ProjectsHelper#foo が直接呼ばれる puts ProjectsController.new.foo # foo
ProjectsController の定義を prepend よりも先に移動した。
ProjectsController には ProjectsHelperPatch が差し込まれる前の ProjectsHelper を include していることになる。
結果 ProjectsHelperPatch#foo は呼び出されず ProjectsHelper#foo が直接呼び出されるので ProjectsHelperPatch によって動作を上書きできていない。
Redmine と Redmine プラグインのロード順
Redmine プラグインは Redmine 本体コードの app/ 以下よりも先にロードされる。(config/initializers/30-redmine.rb) なので、プラグインのなかで prepend すれば app/ 以下のコードを上書きできる。
プラグインで Controller をロードすると後続で helper を prepend しても有効にならない
プラグインでこういうコードを書いたとする。
ProjectsController.prepend(ProjectsControllerPatch) # (1)
別のプラグインで ProjectsController が include している ProjectsHelper を prepend していたとする。
ProjectsHelper.prepend(ProjectsHelperPatch) # (2)
(2) の prepend は (1) より先か後かで有効になったりならなかったりする。
(1) が先に実行された場合はこの時点で include される helper には (2) は prepend されていないので ProjectsController には (2) の動作が付加されない。
フォルダ名順にロードされるので、フォルダ名によって動いたり動かなかったりする。
(2) を開発していてロードされない原因が関係ない (1) のプラグインのせいだと気づくのは無理があるので非常にやっかい。
まとめ
Redmine プラグインで Controller をロードしてはいけない。
わたしです → https://github.com/suer/redmine_recent_project_accesses/commit/24c5d3939385d8e1ce966a750d12749b9d7902b9#diff-242d0b4ac43f99fbb7c9023c1aca7166R4