私のホームページはSinatraでできています
背景
Sinatra が 4.2.0 になり PATH_INFO の扱いが変わりました https://github.com/sinatra/sinatra/compare/v4.1.1...f53a68482f3d5a1a868320f5da3ca7e14bfd8fdf
それに伴いルーティングの定義を仕方も変わったのでそれに対応しました
結論
ちゃんと get '/' do ... end
を使いましょう
仕組み
自分のホームページは各ページをクラスとして定義しています
例えば /about を管理するページは以下のようにクラス化されています
# frozen_string_literal: true
require './libs/ogp'
require './controllers/base_page'
# 自己紹介ページのルーティングを定義するクラス
class AboutPage < BasePage
def initialize
@path = '/' # config.ru 側でパスを指定するのでここはすべて / になる
@real_path = '/about' # sitemap 生成用のパス
@tpl_name = :about
@title = 'About @kakakikikeke'
@description = '興味のある分野、職歴、資格について紹介しています'
@image = OGP::DEFAULT_IMAGE
@sitemap = { priority: 0.8 }
super(@real_path, @sitemap)
routing
end
def routing
AboutPage.get @path do
@ogp = OGP.new(@title, @description, @path, @image)
erb @tpl_name
end
end
end
でこのクラスを config.ru
で Rack::URLMap を使って読み込み
# frozen_string_literal: true
require './libs/routing'
run Rack::URLMap.new(Routing.definition)
展開しています
# frozen_string_literal: true
Dir[File.expand_path('../controllers', __dir__) << '/*.rb'].sort.each do |file|
require file
end
# ルーティングを定義するモジュール、ちゃんとメニューの順番と同じになるようにrouting.jsonを定義すること
# また動的に生成するページは各Pageクラス内で定義すること
module Routing
def self.definition
JSON.parse(File.read('./routing.json'))['routing'].map do |info|
[info['path'], Module.const_get(info['class']).new]
end.to_h
end
end
今回の現象
上記のように展開すると本来は 200 が返るのですがなぜか 404 になるようになってしまいました
対応策
で結果的に対応策は以下のようになりました
各ページで定義しているルーティング情報をメソッド内で呼び出すのではなくちゃんとクラス配下に定義してあげるようにしています
# frozen_string_literal: true
require './libs/ogp'
require './controllers/base_page'
# 自己紹介ページのルーティングを定義するクラス
class AboutPage < BasePage
PATH = '' # config.ru 側でパスを指定するのでここはすべて空になる
def initialize
@real_path = '/about' # sitemap 生成用のパス
@tpl_name = :about
@title = 'About @kakakikikeke'
@description = '興味のある分野、職歴、資格について紹介しています'
@image = OGP::DEFAULT_IMAGE
@sitemap = { priority: 0.8 }
super(@real_path, @sitemap)
end
AboutPage.get PATH do
@ogp = OGP.new(@title, @description, PATH, @image)
erb @tpl_name
end
end
- @path を PATH として定数にする
- かつ PATH は必ず空にする
- routing メソッドを削除し get を直接クラス配下に定義する
これで一応動作するようになりました
おまけ: Rack::Lint::LintError: uppercase character in header name: Content-Security-Policy (Rack::Lint::LintError)
CSP ヘッダなどをミドルウェアで定義する場合は大文字を使ってはいけないようです
# frozen_string_literal: true
require './libs/routing'
# 静的ファイルに対するヘッダーを設定するミドルウェア
class StaticHeadersMiddleware
def initialize(app)
@app = app
end
def call(env)
status, headers, body = @app.call(env)
path = env['PATH_INFO']
if path =~ %r{^/(robots\.txt|favicon\.ico|img/|js/|css/|ipa/)}
headers['content-security-policy'] ||= "default-src 'self';"
headers['cross-origin-embedder-policy'] ||= 'require-corp'
headers['cross-origin-opener-policy'] ||= 'same-origin'
headers['cross-origin-resource-policy'] ||= 'same-origin'
headers['permissions-policy'] = 'camera=(), microphone=(), geolocation=(), fullscreen=(self)'
end
[status, headers, body]
end
end
use StaticHeadersMiddleware
run Rack::URLMap.new(Routing.definition)
最後に
メソッド内で get などを定義すると実際にアクセスされた際にルーティングの定義が見つからずエラーになるようです