はじめに
Rails 5.1で動的に生成しているページを静的ファイルとして保存しておきたい。
ググってみてもスタンダードなやり方が見つからなかったので、少しハックな感じもするけど独自の方法を考えてみた。
やり方
下記2個のファイルを作成する。
lib/tasks/docs.rake
desc "ページを静的化する"
task "docs:generate" => :environment do
DocsGenerator.new.generate_all
end
app/models/docs_generator.rb
# 静的ドキュメントファイルを生成するクラス
class DocsGenerator
# 出力先ディレクトリ
SAVE_DIR = Rails.root.join('static_docs')
def initialize
# 静的化したいページのURLと保存先パスをここに書く
@urls = [
{
url_path: "/",
save_path: "/index.html",
},
{
url_path: "/hello",
save_path: "/hello.html",
},
]
end
def generate_all
# Rails consoleで使えるのと同様のappオブジェクトを作成する
# https://stackoverflow.com/a/20022165/5209556
app = ActionDispatch::Integration::Session.new(Rails.application)
@urls.each do |url|
generate_one(app, url)
end
end
private
def generate_one(app, url)
# リクエスト発行
app.get(url[:url_path])
# レスポンスをファイルに保存
save_path = SAVE_DIR.join(url[:save_path].sub(%r{^/}, ''))
FileUtils.mkdir_p(File.dirname(save_path))
File.write(save_path, app.response.body)
if !File.exist?(save_path)
puts "Error: #{save_path} を作成できませんでした。"
elsif File.size(save_path) == 0
puts "Warning: #{save_path} のファイルサイズが 0 です。"
else
puts "Wrote: #{save_path}"
end
end
end
@urls
のところに静的化したいページのURLと保存先パスを書いておくことに注意。
もともとドキュメントを生成するために使っていたのでクラス名がDocsGenerator
になっているけど、その辺は適宜変更してほしい。
あとはコマンドラインから
bin/rake docs:generate
を実行するだけ。./static_docs
ディレクトリ内に静的htmlファイルが生成されているはずだ。
解説
Railsにもともとある機能として、bin/rails c
のコンソールの中で
[1] pry(main)> app.get "/"
のようにすると /
へリクエストを発行することができる。
この app
オブジェクトを普通のモデルの中で使えないかと思って調べてみたところ、Stack Overflowによると
app = ActionDispatch::Integration::Session.new(Rails.application)
でできると書いてあったので、これを使っている。
ここは将来のRailsでも動くかどうか確信が持てないところ。
もっといいやり方があったら教えてください。