railsアプリを開発していると、自作DSLだとか設定ファイルを読み込んで何らかの処理を実行するということがよくある。その際に問題になるのは、設定ファイルを変更するたびにいちいちサーバを再起動しないといけないということ。小さなアプリならまだしも、そこそこの規模になってくると、再起動にも結構時間がかかてしまい、鬱陶しいことこの上ない。そこで特定のファイルを監視しておき、更新されていたら次回リクエスト時に特定の処理を走らせることにする。
目次
環境
- ruby on rails 4, 5
For Rails 5
まずは rails 5 のコードから。次のコードを適宜編集して、config/initializersの下に置く。
📄config/initializers/reloader_rails_5.rb
unless Rails.env.production? reloader = Rails.application.config.file_watcher.new(['path_to_file']) do # do_something end Rails.application.reloaders << reloader ActiveSupport::Reloader.to_prepare do # reloader.execute <=他のファイルが更新されても実行するならこちら reloader.execute_if_updated end end
なにをしているかというと、まずRails.application.config.file_watcher
でファイルの更新監視クラスを取ってきている。普通はconfig/environments/development.rb
には次のような設定がしてあるはずなので、
📄config/environments/development.rb
config.file_watcher = ActiveSupport::EventedFileUpdateChecker
ActiveSupport::EventedFileUpdateCheckerクラスが取得できるというわけだ。こいつに監視対象のファイルパスを渡し、ブロック内に実施したい処理を書けばよい。
次に、ActiveSupport::Reloader.to_prepare
の部分だが、何らかのファイルに更新があった次のリクエスト処理時に、このブロックが実行されることになっている。ここで先ほど生成したreloaderを実行してやればよい。
reloader.execute_if_updated
というのは監視対象のファイルが更新された場合にだけreloaderを実行する。通常はこのメソッドを使えばよいと思う。他のファイルが更新された場合でもreloaderを実行したい場合はreloader.execute
だ。
For Rails 4
基本的にはrails 5と同じなのだが、少しだけ使用するクラスが違う。
📄config/initializers/reloader_rails_4
unless Rails.env.production? reloader = ActiveSupport::FileUpdateChecker.new(['path_to_file']) do # do_something end Rails.application.reloaders << reloader ActionDispatch::Reloader.to_prepare do reloader.execute_if_updated end end
やってることはrails 5と同じなので、説明は省略。
実例(rails 5)
📄config/initializers/reloader.rb
ymls = Dir.glob("#{Rails.root}/app/dsls/config/search/*.rb") ymls.each { |yml| load yml } unless Rails.env.production? ymls.each do |yml| reloader = Rails.application.config.file_watcher.new([yml]) do load yml end Rails.application.reloaders << reloader ActiveSupport::Reloader.to_prepare do reloader.execute end end end
実際に私が使用している例。自作DSLがyamlファイルを読み込むのだが、yamlを変更する際にサーバを再起動しないでいいように、上のようにしてみた。
もともとは、settingslogicという定数管理用のgemを使用していたのだが、yamlを変更するとサーバを再起動しないといけないのが嫌で、解決策を探してみた。
ちなみに拙作の定数管理gemは、サーバを再起動しなくても、定数を記述するyamlを変更したら自動でリロードするようにしてある。
その中のここのソースでrails4と5を切り替えてreloaderを登録するようにしているので、gemを作る人なんかには参考になるかもしれない。
関連する記事
- 久しぶりにRailsで開発して感じたこと
- Railsアプリ内の定数を管理するgem ‘Constantinopolis’
- rubocop + pre-commitで規約違反のコードをコミットできないようにする
- Ruby on Rails + Bootstrap3 + simple_form チュートリアル
- Rails 4.1 + devise + omniauth-google-oauth2 で認証機能を実装する