Rails 7は未来だ

このブログもそこそこ投稿がたまってきつつある今日この頃。 きっかけはたまたま昨日Stimulusのチュートリアルを読んで、Turboのチュートリアルを読んで今日に至る。 そしてRails 7ではこれらの技術がOut of the boxなのである。 正直なところまだチュートリアルを読み進めている段階で良くも悪くも集中力が切れてしまうので、この気持ちを今のうちにブログに残すことにした。

Stimulus Handbook

まずはStimulusから始めよう。

このチュートリアルではstimulus-starterがあらかじめ用意されているが、Rails 7を作成した状態で問題ない。 そもそもStimulusというものが登場してからしばらく経つ。 少なくとも私はバックエンドとフロントエンドのディレクトリをどうやって運用しようだとか、この頃はRails APIばかり書いていた頃だったかもしれない。 Webpackerの開発体験がCreate React Appなどに比べると劣ることから、Rails 6にはあまりいい思い出がない。 少なくとも趣味でRailsを使ってWebアプリケーションを作っていた頃は全く利用していなかった。 それがちょうどCreate React Appが使えなくなってWebpackerに回帰しようとしていた時期だったはずだ。

長々と書いているが、この頃すでに私は道を誤っていたのかもしれない。

だからStimulusがアナウンスされた当時や、Rails 7がリリースされた頃も基本的にはあまり関心を払っていなかった。 とはいえ私だけがそこまで殊勝な立場とは思っていない。 薄々だがRailsは昨日の言語としてどこか捉えられている節がある。 しかしRailsがこれまで築いてきたエコシステムから脱却しきれずにいるのも事実であった。 だから最新の技術でなくなり、昔ほど注目されなくなったとしても私にとっては些末なことなのだ。

Reactを書くのは今でも好きだし、それ自体が非常に理にかなっていると思う。 世間もNext.jsやDeno、最近はBunなどで盛り上がっている。 Prismも宣言式のファイルでmigrationが生成されるし、開発体験は素晴らしいとは思う。 思うけれどもやっぱりバックエンドはRubyで書きたい。 Rubyだって別に言語としての開発が止まっているわけでもない。 PythonやTypeScriptの登場、PHPが盛り返したりしている中でRubyも気づいたら3系をリリースしたと思ったらすでに3.2をリリースしている。 余談だが3系を使うまでも実は長くて、あえて2.7ばかり使っていた。 これまでの経緯からgemの問題を気にしていたが、少なくとも趣味で使っている分には3系特有のエラーに出くわしたことはない。

かなり脱線してしまったが、Stimulusに話を戻そう。 JSXや、Vue、最近はMarkoというテンプレートエンジンも目にしたのだが、これらのエンジンはやはりJSファーストである都合上受け入れられるようになるまでは違和感が残る。 対してStimulusはdata属性をうまく利用しているため、HTML5の標準に則っている。

<div data-controller="hello">
  <button data-action="click->hello#greet">Greet</button>
</div>
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  greet() {
    console.log("Hello, Stimulus!")
  }
}

最も簡単なStimulusの例はこうだろう。 data-controller="hello"で上記のHTMLとJSがペアになっている。 click->hello#greetでイベントとコントローラ、メソッドがそれぞれ紐付いているので、GreetをクリックすればHello, Stimulus!がコンソール上に出力される。

コントローラというくらいだし、記述の仕方も似ているのでRails脳で考えるとそれぞれページ単位で1つのStimulusのコントローラを紐付けることを想定しがちだ。 ただしStimulusの興味深いところは複数のDOMに対して指定できるし、上記のdata-controller="hello"を持つDOM要素に対してクリックさえできれば何でもgreetが使える。 だからDIVタグだけではなくFORMタグやARTICLEタグであろうと使えるし、このコードならBUTTONタグもAタグに置き換えたり、すべてがDIVタグであってもよいと思う。 ReactやVueのようにコンポーネントに対して1つのファイルとはまた異なり、Stimulusはdata属性に紐づくコンポーネントという概念を生み出している。

ReactではuseStateuseEffectなんかのhook関数を多用するし、独特の構文は初学者にとって抵抗は大きい(誰しも一度はAjaxの無限ループを経験するだろう)。 あくまでdata属性だけだから、jQueryのように手続き型で書いたコードがごちゃまぜになる恐れもなさそうだ。 ただしRailsはERBが使えるので根本的に防ぐことはできない。

Stimulus単体での記述でもよさそうだが、ViewComponentとの親和性は高そうに思った。 単純にテンプレートにしてrenderできるようにしてもよいだろう。 JavaScriptとRubyのテストコードのディレクトリも分かれているし、テストは一箇所で管理できないので探すのが手間になりそうな予感はしているが、Rubyらしさを組み合わせてできているのは非常に好ましい。

Build modals with Hotwire in Rails (Turbo Frames + Stimulus)

import { Controller } from "@hotwired/stimulus"
import * as bootstrap from "bootstrap"

export default class extends Controller {
  connect() {
    this.modal = new bootstrap.Modal(this.element)
  }

  open() {
    if (!this.modal.isOpened) {
      this.modal.show()
    }
  }

  close(event) {
    if (event.detail.success) {
      this.modal.hide()
    }
  }
}

後ほど紹介するページに素晴らしい例があった。 まだ実際に動かしたわけではないが、このコードが意図する使い方は安易に理解できる。 StimulusでもRailsのコントローラのように極力スキニーに保つようにするとよさそうだ。 Reactでよくやるコンテナコンポーネントの考え方にも近いと思う。

Turbo Rails Tutorial

Stimulusのチュートリアルは比較的すんなり終わったのだが、Turboに関しては公式のチュートリアルよりもHotrailsというサイトが参考になりそうだ。 実践的で内容が濃いので非常にありがたい。 良質なチュートリアルといえばRails Tutorialがフリーで公開されていた当時を思い出す。

Turboは前出のTurbolinksと同じものだと思っていた。 Turbolinksという単語でpjaxとかが出ていた頃を思い出すけれども、TurbolinksのおかげでRailsとJSのライブラリをページごとに組み合わせることができた。 使い方を覚えるまではTurbolinksが逆にjQueryのイベントを打ち消す原因だったので毎回インストールしないようにしていた。 大きな違いである。

使い方を調べなければTurboもTurbolinksと実はそこまで変わらないけれども、やはりturbo_frame_tagには衝撃を受けた。 Stimulusだけでも感銘を受けたのに、turbo_frame_tagはJavaScriptすら書く必要がない。 もともとTurboはJSが必要ないというのはDHHのYouTubeでも紹介されていたが、その当時はいまいち理解しきれなかったのだ。

JSで書く必要がないというのは単純にReactやVueのようにJavaScriptで記載する必要がないという意味に留まらずに、JavaScriptが実行できない環境ですら動作できるという意味である。 近年はブラウザのJavaScriptをOFFにしたままでネットサーフィンは難しい。 Next.jsなどをはじめとするJS系のサーバーレンダリングはあくまでSEO対策のためだけという感じがする。 JavaScriptで記述しているのだから、自らのアイデンティティを否定するはずがないといえば当たり前ではあるが。 Railsが好ましいのはあくまでJavaScriptはページを快適に表示するための手段に過ぎないからだ。 StimulusでもJavaScriptがサポートされていないブラウザのことを想定しているのは先程のチュートリアルでも確認できる。 書き方は冗長だが、無理のない範囲だ。

Turbo Rails Tutorialでも最初にテストを書くところから始めるのだけれども、turbo_frame_tagを実装している最中はテストが落ちなかった。 これは単純に私がCapybaraのテストをrack_testに指定していた勘違いが原因だったのだが、たとえJavaScriptが機能していない状況でもブラウザと同じテストケースを書くことができる。 つまりページとしての機能はすべて誰でも等しく享受することができるのだ。 このブログでリチャード・ストールマンのページを紹介するのは2回目だが、The JavaScript Trapに対する回答にもなり得ると思う。

Gmailの「簡易HTML形式」が2024年1月に終了予定、テキスト読み上げツールを使う視覚障害者の不利益になる可能性も

Googleが長年提供し続けてきた簡易HTML形式のサポートを打ち切るらしい。 なぜわざわざ自分たちがサポートしていたものを取りやめるのか、そこにはビジネス上の理由もあるかもしれないがきっとJavaScriptに依存しきった開発だとHTMLのみのページの開発が障害にしかならないのだろう。 TurboはJSのページとHTMLのページがそれぞれ同じデザインなのでこのあたりが破綻する心配はずっと少ない。 やれReactでrole要素の抜けを指摘する以前に、まずはこういう根本的なところをもっと見直すべきだったのではないだろうか。 そう考えるとRailsはこれを見越していたのだとしたら、Railsは最初からずっと真っ直ぐに伸びているレールの上を地道に走り続けていたのだと思う。

それにいくらReactを使っていると言っても、結局やることの大半はステート管理に大量のajaxコールである。 あくまで私の場合はだが、SPAなのにReact Routerを使って気づいたらRailsもどきを再現している。 RailsならわざわざJSON形式に変換したり、GraphQLなんか利用しなくてもインスタンス変数経由でそのままRubyのオブジェクトを渡せるのに。 それでもERBよりもJSXのほうが直感的だから意味はあると思うのだけれども、Railsだって別にReactで出来ることの大半はJavaScriptが使えれば再現できる。

だからわざわざReactである必要がないのかもしれない。 最悪なのはもともとRailsで出来ていたものをReactなどにすべてリプレイスしてしまった場合だ。 しかもRailsが差し伸べている手を振り払ってまで!

この最たる例といえばGitHubやGitLabなどを想像してほしい。 なにかページやサイドメニューを開くたびにスピナーアイコンが表示される。 プログレスを表示することは私のブログでも触れているが、それ自体の実装は別に悪くはない。 問題なのはページに含まれる何もかもが読み込み状態に陥っている昨今のウェブアプリケーションはなんだか歪だ。 スピナーの表示はせいぜい1つか多くても2つくらいにしておかないとページ上の表示は早いとしても却って遅いと感じるのは私だけだろうか。 これは私の想像だが、スピナーをつけると楽しくなって必要以上に回したくなってしまうのかもしれない。

話は逸れたが上記のTurbo Rails TutorialはすべてのRailsエンジニアたちが一度は抑えておくべき内容だと思う。 それどころかRailsを離れたエンジニアたちですらこの開発体験を今一度体験しておくべきなのではないだろうか。 Webの世界はPHP、Java、Pythonなどに加えてRustやGo、C#などの勢力もいるので一概に最高とは言い切れないのだけれども、Hotwireは間違いなくJavaScriptファーストの開発に一石を投じるムーブだと感じる。 私はWASMの世界には疎いので、ひょっとすると他の言語は脱JavaScriptといえばそういう方向が現実的かもしれないが、Rubyは過去の資産も活かせるし、間違いなくこの道を進むべきだと確信した。

他にもTurboを学ぶ大きなモチベーションのひとつとしてはWebSocketがある。 RailsはすでにActionCableがあるので必ずしもTurboだからWebSocketを使えるという理由もない(Turboのチュートリアルをすべて読み終わる前に書いた文章はコメントアウトしてあるので興味があれば見てほしい)。

多少駆け足の部分もあったのだが、一通り読み終えた感想としてはbroadcast_toといったメソッドを始めとしてJavaScriptを書かなくてもページが勝手に書き換わるのは心地よい。 ただし従来のCRUDのように一定の型にはめられるほど簡単に制御できるとも思わなかったのでここは注意が必要である。 それでもこれまでRailsで書くよりはWebSocketが身近に扱えるようになったのも事実ではあるので、徐々に取り込んでいきたいとは思った。

何よりこういった諸々の技術がもうすぐに使える状態だったのに、私はあえてそこから目を反らし続けていた。 今までのやり方ではない技術を学ぶのには大変気力を使う。 現行のやり方でもWebページは作れるのだが、はじめてReactの世界に飛び込んだ頃やRubyを捨ててNode.jsでサーバーを書こうと思い立った頃もきっと似たような心境だったはずだ。

どれだけ時間をかけて学んでも、最終的に今後採用し続けるかはまだわからない。 それでも私がrails newするとき--minimalを選ぶことは少なくなるだろうし、APIモードではない本来のRailsに原点回帰できることを喜ばしく思う。 この投稿をきっかけに少しでもHotwireを試してみたいと思えたらそれだけで私は幸せだ。 それでも最後にもう一度。

Rails 7は未来だと思う。