【Rails】リロード時に特定の処理を実行する


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を作る人なんかには参考になるかもしれない。

関連する記事


コメントする

メールアドレスが公開されることはありません。

CAPTCHA


このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください