Tech Racho エンジニアの「?」を「!」に。
  • Ruby / Rails関連

Rails: TurboとViewComponentを使うときの注意点(翻訳)

概要

元サイトの許諾を得て翻訳・公開いたします。

日本語タイトルは内容に即したものにしました。

Rails: TurboとViewComponentを使うときの注意点(翻訳)

私たちのプロジェクトでは、ビューテンプレートのボタンスタイル統一にViewComponentを使っています。たとえば以下のような感じです。

class Forms::Button < ViewComponent::Base
  def initialize(type:, text:, options: {}, data: {}, disabled: false)
    @type = type
    @text = text
    @options = options
    @data = data
    @disabled = disabled
  end

  def call
    case @type
    #...
    when "link"
      link_to(
        @options[:href],
        data: @data,
        class: "#{@options[:text_color]} #{@options[:bg_color]} #{css_styles} app-btn",
      ) do
        tag.p(@text)
      end
    end
  end

指定されたコンポーネントでPOSTリクエストを行うために、link_tomethodオプションを使うことに決めました。

  #...
  link_to(
    @options[:href],
    method: @options[:method] || "GET",
    data: @data,
    class: "#{@options[:text_color]} #{@options[:bg_color]} #{css_styles} app-btn",
  )
  #...

これは動きましたが、ひとつ問題がありました。他のコンポーネントのリンクが動かなくなってしまったのです。

link_tomethodオプションを指定するとHTMLフォームを動的に作成して即座に送信します。これは@rails/ujsを使っていますが、GETフォームがTurbo Streamsのレスポンスと互換性がないことが判明しました。

修正方法は、この:methodオプションを削除し、button_tagを用いて:postリクエストを送信することでした。

さらに申し上げると、Rails 7では@rails/ujsライブラリがデフォルトではなくなりました。また、link_tomethod属性も非推奨になったので、使ってはいけません。

訳注

本記事ではbutton_tagを用いる形で解決していますが、最新のRailsガイド(v7.0.4)に示されているように、data:turbo_methodを使えばlink_toでも一応HTTPメソッドを変更できます↓。ただしアクセシビリティの観点から、非GETメソッドはリンクではなくボタンとフォームにするのが望ましいとも書かれています。

<%= link_to "Delete post", post_path(post), data: { turbo_method: "delete" } %>

Rails APIドキュメントlink_toには、method: HTTPメソッド名のシンボルremote: trueconfirm: "確認メッセージ":disable_withの4つがRails UJS由来の属性としてRails 7以降は非推奨と書かれています。

お知らせ: 5600人以上のRailsエンジニアが購読しているメールマガジン

元記事末尾のフォームに登録いただくと、Arkencyのベテランプログラマーによる磨き抜かれた洞察や知恵を結晶したメールマガジンを配信いたします。

私たちは皆さんのメールボックスにスパムを決して送信することのないよう最大限に配慮しています。フォームを送信いただくと確認メールが届きます。

関連記事

Rails: Webpackをesbuildに移行してJSのビルドを縮小・高速化(翻訳)

実践ViewComponent(1): 現代的なRailsフロントエンド構築の心得(翻訳)


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。