Rails5から外部HTMLを読み込む方法
既にHTMLでページが出来上がっているけど、
その完成した静的HTMLをRails5から出力する方法を考えてみました。
これが出来れば静的なHTMLなどに対してアクセスした際の追加処理をRails5上で加える事が可能です。
やり方概要
- routesファイルで全てのパスへのアクセスを1つのアクションにまとめる。
- action上ではファイルの存在チェックやHTTPレスポンスを返す。
これだけでRails5上から静的HTMLを返す事が可能です。
実際に具体的な処理を見ていきます。
事前準備
Railsアプリケーションルートディレクトリ配下にprivateディレクトリを作成し、その中に下記ファイルを格納します。
通常静的ページはRailsアプリケーションルート/publicディレクトリにHTMLを格納しますが、
今回はpublicディレクトリ配下ではなく別ディレクトリに格納した前提で進めていきます。
- a.html
- a.css
- a.js
- a.png
それぞれのファイルの内容を見ていきます。
<!DOCTYPE html>
<html>
<head>
<title>title</title>
<meta charset="utf-8">
<script type="text/javascript" src="a.js" charset="UTF-8" ></script>
<link rel="stylesheet" type="text/css" href="a.css"></link>
</head>
<body>
<h1>abcddefghlj</h1>
<img src="a.png" />
</body>
</html>
window.onload = function() { window.alert('aaaa') }
h1 {
border-bottom: solid 2px red;
}
a.pngは好きなpngファイルを格納してください。
Routesファイルを一つのアクションを参照するように修正
下のコードのように処理を修正します。
具体的にはルートディレクトリやその他全体のパスに対して、
static#show
を動作させるようにしています。
Rails.application.routes.draw do
root 'static#show'
get '*path', to: 'static#show'
end
上記は こちらを参考にしました。
静的HTMLを返すアクションの作成
class StaticController < ApplicationController
def show
# request pathを取得
private_root_path = "#{Rails.root}/private/"
file_path = File.expand_path( File.join( "#{private_root_path}" , "#{request.path_info}" ) )
# railsルート以外のディレクトリやファイルが存在しない場合
if !file_path.start_with?( "#{private_root_path}" ) || !File.exist?(file_path) || File.directory?(file_path)
render file: "#{Rails.root}/public/404.html", layout: false, status: 404, content_type: 'text/html'
return
end
# ファイルが存在する場合
respond_to do |format|
format.js { send_data File.read(file_path), :type => "application/javascript" , :disposition => "inline" }
format.css { send_data File.read(file_path), :type => "text/css" }
format.png { send_data File.read(file_path), :type => "image/png", :disposition => "inline" }
format.json { render json:"json" }
format.html {
# render html: File.read(path).html_safe
render file: "#{file_path}", layout: false, status: 200
}
end
end
end
このコードで少なくとも js,css,png,htmlはブラウザ上に返すことが出来ます。
以上が静的HTMLを返すRailsのサンプルです。
実際に試してみた。
htmlの表示やJavascriptの動作などが行えている事が確認できます。
おまけ
アクションを追加したい場合
上で記載したコードだと全てのパスに対して1つのアクションが呼び出されますので、特定URLにアクセスしたい場合のアクションを追加する方法を記載しておきます。
具体的には下記コードの追加です。
Rails.application.routes.draw do
get '/special', to: 'static#special' # add line
root 'static#show'
get '*path', to: 'static#show'
end
# 下記アクションをStaticController内に追加
def special
render html: "special html!!"
end
これで URL/specialというようにアクセスした場合は、
StaticController#Specialというアクションが実行されます。
CVE-2019-5418 問題
どうも render fileを使用した場合に発生するセキュリティホールがあるようです。
上記コードを使用する際は各々使用しているRailsVersionを確認してください。
こちら が参考になると思います。
読んでいただきありがとうございました。
Railsを学び始めたところですので、
誤りや問題点・指摘などがある記事になっているかもしれません。
もし何かありましたらご指摘お願いします。
またコメントやこうしたら良いよみたいなアドバイスがあればコメントいただけると嬉しいです。
特に上記Rubyのアクションコードを記載していますが、行数が長くもう少し短くしたいです。