日本の郵便番号データを扱うRuby gemとしてはzip_code_jpが有名です。ECサイトなどでは郵便番号から住所を補完する機能はもはや当たり前になっていますが、そのような機能を作りたいときに便利なライブラリです。

この郵便番号データはZipCodeJp.export_jsonで更新できますが、このときgemのdata/zip_codeディレクトリ内にあるJSONファイルを直接更新します。 一般的なサーバ環境であればcronで回すなどすれば普通に更新できますが、Herokuの場合はローカルにファイルを書き込んでも再起動のタイミングで自動で消滅します。Heroku Schedulerなどで定期実行しても、既にパッケージされたslug内のデータは変更できないので意味がありません。 Release Phaseでいけないかな?とも思いましたが、Release Phaseはslugのビルド後に実行されるのでこれも使えません。

どうしようかなと考えた結果、デプロイ時に更新処理を実行するようにして、slugに最新の郵便番号データを入れてあげることにしました。

lib/tasks以下に適当な名前でRakeタスクを作り、以下のように書きます。

# lib/tasks/heroku_deploy.rake
Rake::Task['assets:precompile'].enhance do
  Rails.logger.info 'Update zip code data'
  ZipCodeJp.export_json
  Rails.logger.info 'Done!'
end

任意のタスクのあとに別のタスクを実行するため、Rake::Task#enhanceを使っています。ドキュメントには「自身に事前タスクとアクションを追加します。」としか書かれておらず使い方がわかりにくいですが、enhanceの引数に指定したタスクは事前に実行され、ブロック内に記述したタスクは事後に実行されます

Herokuへのデプロイ時にはassets:precompileが毎回実行されるので、Rake::Task['assets:precompile'].enhanceとすることで、デプロイ時に任意のタスクを実行できるようになります。ここで郵便番号データを更新するようにしました。 郵便番号データ更新に限らず、デプロイ時に実行したい処理があれば同じように書けます。

更新にかかる時間は約20秒でした。少し時間はかかりますが、デプロイのたびに最新の郵便番号データを含めることができるので安心ですね。

remote:        I, [2018-08-28T17:24:33.195355 #823]  INFO -- : Update zip code data
remote:        I, [2018-08-28T17:24:55.116512 #823]  INFO -- : Done!

(もし毎回実行されるのが気に入らなければ、前回の実行日をどこかに覚えておくとか、日付を見て○日にのみ実行する…といった方法が考えられます)