🤖
Turbo Frame + Railsでflashメッセージを表示する方法
Turbo Frameめちゃくちゃ便利なんですが、Flashメッセージが返せないという問題点があります
一応turbo streamなどで返す方法はあるんですがRailsのデフォルトのflash[:error] = "hoge"
とかで返せるようにしたいなーと思ってたので適当に組んでみました
仕組み
- Railsのデフォルトのflashにいつもどおり突っ込む
- turbo_frameを読み込むときにFlashにメッセージが入ってればそれをHeaderに入れて返す
- Tubo側でHeaderにFlashメッセージが設定されていたらjsで良い感じに表示する
こんな感じです!同じような問題を抱えてる人いたら自分の環境に合うように適当に書き換えて使って下さい
1. application_controllerに適当にメソッドを生やす
after_action :flash_turbo_frame
def flash_turbo_frame
return if response.redirect?
message = {}
if turbo_frame_request?
message = flash.inject({}) do |hash, (type, _message)|
# XSS対策&日本語のエスケープ
hash[type] = CGI.escape("#{ERB::Util.html_escape(_message)}")
hash
end.to_json
flash.discard
end
response.set_header(
'X-Flash-Messages',
message
)
end
return if response.redirect?
リダイレクトがかけられた時は一旦スルーする
after_action
これでcontrollerのあれこれが終わった後に処理できます
if turbo_frame_request?
これでturbo_frameでの読み込みだけ対応する
flash.discard
これでflashを消す(残しちゃうとRails側でもう一度表示されてしまう)
2. jsで適当に対応する
document.addEventListener('turbo:before-fetch-response', function(event){
var json = JSON.parse(
event.detail.fetchResponse.header('X-Flash-Messages')
)
// メッセージを表示する
for(let key in json){
// ↓ これがflashメッセージを出すfunction
flash_submit(
key,
decodeURI(json[key])
)
}
})
もっといい方法がある気もしますが暫定でこんな感じでどうでしょか!!
Discussion