railsのcontrollerの出力をhtmlファイルとして外部にアップロードする

概要

railsアプリは、ブラウザからのアクセスがあると毎回新しいHTMLを生成しているけど、RSSリーダーのように、常に最新のHTMLを返さなくていいという要件がたまにある。そういうときは、railsを常に起動しておく必要はなくて、定期的にrailsがS3とかにHTMLをアップロードすれば、railsのランニングコストをかなり減らせる。
(例: CloudRunにrailsを立ててスケジューラーで定期アップロードする。 )

本テキストでは、railsが定期的にHTMLをアップロードするための実装について書いてみる。

本文

基本的な方針は、以下の通り

  • controllerでHTMLを生成するときは、controller/viewを横断する自作クラスを呼び出す
  • アップデートで壊れやすいので不用意にハックをしない

これらをコードにすると以下のようになる。

class MarshmallowsController < ApplicationController
  class HTMLRenderer
    def initialize
      @marshmallows = Marshmallow.order(published_at: :desc)
    end

    def render
      ApplicationController.renderer.render_to_string(
        template: 'marshmallows/index',
        assigns: { marshmallows: @marshmallows },
        format: 'html'
      )
    end
  end

  def index
    render html: HTMLRenderer.new.render
  end
end

ApplicationController.renderer.render_to_stringを使うだけ。
HTMLにアップロードする処理は、controllerで呼び出しているクラスを読んでHTMLに書き出すだけ。

class HtmlDumper
  def self.execute!
    Rails.logger.info 'Dumping HTML'
    html = MarshmallowsController::HTMLRenderer.new.render

    Rails.root.join('public/dump.html').tap do |path|
      File.open(path, 'w') do |file|
        file.write html
      end
    end

    # S3へアップロードする
  end
end

まとめ

趣味アプリケーションを低コストで動かすことができるアイディアについて書いた

余談

  • HTMLRendererクラスは、リフレクションを使えばもっとシンプルになって、クラスマクロとかで完結できそう
  • 過去に上記の仕組みを採用したアンテナサイトを作っていた