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 によって動作を上書きできていない。

RedmineRedmine プラグインのロード順

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

rsync でタイムスタンプの違いは無視したい

rsync するときタイムスタンプが違ってもファイルに違いがなければコピーされないようにしたい。

$ rsync --checksum ...

ファイルのチェックサムが一緒ならそのファイルはコピーしなくなる。

ファイルがたくさんある場合は checksum の計算だけで時間と CPU 負荷がかかって大変なことになるので注意。

プロセスがどこにログを吐いているか調べる

知らないフレームワークを使っている Web アプリがどこにログを吐いているか調べるために、そのフレームワークの設定方法を調べるより

$ lsof -p プロセスID

とかしてそれっぽいファイルを探すほうが速かった。

Visual Studio Code をコマンドラインで起動する

確認バージョン

設定

  1. Visual Studio Code を起動する
  2. Cmd+Shift+P (Windows の場合は Ctrl+Shift+P) でコマンドパレットを開く
  3. shell と入力すると Shell Command: Install 'code' command in PATH というのが出てくるのでこれを選択する f:id:suer:20190612202941p:plain:w400
  4. Success と表示されたら成功

コマンド

$ code [パス]

で起動できる。

パスの部分にはファイルのほかディレクトリも指定できるので、プロジェクトトップに cd してから

$ code .

とかしている。

Google スライドの幅の設定

Google スライドでスライドを作ったらデフォルトが PowerPoint より横長だったので変更する。

特にデフォルトのままで PowerPoint からインポートすると違和感が半端ない。

「ファイル(File)」メニュー > 「ページ設定(Page setup)」

f:id:suer:20190611235146p:plain

標準(4:3)を選択すると PowerPoint からインポートしても違和感がなくなった。 幅が広いな〜と思ったら設定してみるといいかもしれない。

iPhone のブラウザで 1Passwordから ID/パスワードを入力できるようにする設定

初回起動時に有効にするか聞かれたのかもしれないけど設定されてなくてどこから設定すればいいか困ったのでメモ。

確認バージョン

  • iOS: 12.3.1
  • 1Password: 7.3.2

手順

  • パスワードとアカウント
  • パスワードを自動入力
  • 1passwordを選んで有効化

f:id:suer:20190610202511p:plain:w200

ブラウザでログインフォームにフォーカス時にキーボードの上に「パスワード」が表示され、タップすると 1Password から入力できるようになる。

f:id:suer:20190610202711p:plain:w200

↓「パスワード」をタップ

f:id:suer:20190610202925p:plain:w200

HTTP サーバが TLS1 に対応しているかどうかを確認するコマンド

$ openssl s_client -connect ホスト名:443 -tls1 < /dev/null

-tls1 オプションは TLSv1 指定で接続する。 -tls1-tls1_1-tls1_2 にするとそれぞれのバージョンで接続チェックができる。

サーバが対応してない場合は以下のようなエラーメッセージが出力される。

CONNECTED(00000005)
write:errno=54
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 0 bytes and written 0 bytes
---