🤖

Turbo Frame + Railsでflashメッセージを表示する方法

2021/11/10に公開

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