Turbo Frame ヘルパメソッド: 小林研 Rails Tips (1)

はじめに

astro-notion-blog に移ると宣言していましたが、逆にブログの記事量が減ってしまいました。Notion で下書きはした上で、はてなで展開するのが一番楽そうなのでこの形に戻してみます。

今回、記事をこちらに書き始めたのは、ユカスタ(Yuka’s Studio) でこんな話が出たからでした。

Vlogmasとは、12/1-12/25までの間毎日Vlogをアップする企画のことなんだけど、別にVlogだけじゃなくてよくて、とにかく毎日何かを作ってアップしようって感じ。Reelsでもいいし、なんならストーリーでもいいと思います!とにかく25日間毎日やることがポイントです。

もし一緒にやりたいって人がいたら一緒にやりましょー!なんかユカスタ専用のハッシュタグとか考えてもいいし、参加する人は毎日アップしたものを ⁠👋⏐みんなの告知 にアップしてくれたら、参加しない人も応援できるし

私は Vlogmas ならぬ Blogmas で参戦することにしました。ただし、毎日アップするとなると、astro-notion-blog だと面倒だなということでの返り咲きです。

さて、ネタなのですが Notion だとネタ切れになりそうなので、研究室の学生用にまとめようと思っていた Rails Tips を小出しにして 25 日書きまくろうと思いました。

本題: Turbo Frame とは

最初に取り上げるのは Rails 7 から導入された Turbo Frame に関するヘルパメソッドです。今回、校務支援システムを Rails 3 から Rails 7 に一気に上げたのですが、一部の教員からは非常に反応がよくなったと好評です。基本的にページ遷移が Turbo drive でページの中身だけを書き換えるようになったことによる評価です。ただ、ページ内遷移が非常に多い場面も多く、それらのページでは積極的に Turbo Frame 対応に書き換えています。

Turbo Frame とは、フロントエンドの記述をすることなくサーバサードの記述だけで、SPA (Single Page Application)のような画面書き換えを行う技術です。これまではサーバからは JSON などで情報を渡し、フロントエンドの JavaScript などで DOM を書き換える処理が多く行われていました。Turbo Frame ではこれらの処理は全てフレームワークが自動的に実施してくれる形になります。サーバ側のコードはほとんど書き換える必要はなく、フレームワークが部分的な書き換えを自動的に実施してくれます。サーバ・クライアント間の転送される情報は減らないという点(ほとんどの情報は捨てられるという点)では無駄ではあるのですが、コードを記述する時間はこれまでとほとんど変わらないという利点があります。

具体的には、以下のようなコードを書くだけです(書き換えたい部分だけを turbo_frame_tag で括るだけ)。turbo_frame_tag で囲まれているため、その中のリンクは tubo_frame_tag の部分のみを書き換えようとします。update アクション自体は redirect によりこのページ全体の情報を返却しますが、フレームワークが turbo_frame_tag の中だけを書き換えてくれます。

= turbo_frame_tag "mb_list" do
  - if @foo.flag
    "⚪︎"
    = link_to "→[×に変更]", foo_path(@foo, foo: {flag: false}), data: {turbo_method: :patch}
  - else
    "×"
    = link_to "→[⚪︎に変更]", foo_path(@foo, foo: {flag: true}), data: {turbo_method: :patch}

また、別のアクションやリンクからこの turbo_frame_tag 内の内容のみを書き換えたい場合には、以下のように turbo_frame を指定します。

一方で、turbo_frame_tag 内のリンクで別のページに遷移しようとすると、Content missing となりエラーになります。別のページに遷移するリンクの場合には以下のように turbo_frame に _top を書く必要があります。

= link_to "go to another page", bars_path, data: {turbo_frame: "_top"}

ヘルパメソッドの作成

ここまで来ると Rubist であれば、DRY 欲が湧いてくると思います。まず、application_controller に tf というヘルパメソッドを追加しました。data の中身を書いてくれるものです。最初の引数は Turbo Frame 名です。省略すると _top になります(これの利用が一番多いため)。turbo_method もよく使うので、パラメータ引数で渡せるようにしています。turbo_confirm も同様です。helper_method にしているので、view の中でも使えます。

  # @param [String] turbo_frame Turbo Frame 名
  # @param [Symbol, nil] method HTTP method
  # @param [String, nil] confirm confirm message
  # @return [Hash] Turbo Frame 用の Hash
  def tf(turbo_frame = "_top", method: nil, confirm: nil)
    ans = {turbo_frame: turbo_frame}
    ans[:turbo_method] = method if method
    ans[:turbo_confirm] = confirm if confirm
    ans
  end
  helper_method :tf

また、ページ内リンクでは data も付けてくれると便利なので、dtf も用意します。中で tf を呼んでいるだけです。こちらも helper_method 化しています。

  # @param [String] turbo_frame Turbo Frame 名
  # @param [Symbol, nil] method HTTP method
  # @param [String, nil] confirm confirm message
  # @return [Hash] Turbo Frame 用の Hash (data あり)
  def dtf(turbo_frame = "_top", method: nil, confirm: nil)
    {data: tf(turbo_frame, method: method, confirm: confirm)}
  end
  helper_method :dtf

利用方法

tf の方は主に form_with 内で使います。form_with の data はパラメータ引数なので、dtf が使えないからです。

= form_with model: @foo, data: tf("mb_list") do |f|

一方、dtf は link_to と組み合わせることが多いです。

= link_to "→[×に変更]", foo_path(@foo, foo: {flag: false}), dtf("mb_list", method: :patch)

= link_to "go to another page", bars_path, dtf

おわりに

さて、とりあえず初日の記事は書き始めましたが、25日書き続けることはできるのでしょうか。個人的にも楽しみです。