Open3

Mermaid.jsを試す

waddy-integrationwaddy-integration

Railsでも非同期なUIを提供したい

Railsでviewを書いている人(haml, slim, erbなどで普通に出力している人)は、非同期のフォローボタンやいいねボタン、検索でサジェストを出すなど「ほんのちょっとだけ今風なUIを提供したい」時にどんなアプローチを取っているでしょう?

多くの人は「jqueryで頑張っている」と答えるでしょうし、最近のはやりを取り入れた人なら「reactでcomponentを差し込んでいる」などと答えるかもしれません

jQueryはすぐにスパゲッティになるし記述量が多い

これはjQueryがフレームワークではなく、ライブラリだというのも大きな原因なんですが、jqueryでリッチなUIを提供しようとすると記述量が跳ね上がりすぐにしんどくなります

ここらへんは恐らく多くの人が実感として持っている事でしょうし、そうでなくても「今の時代もうjQueryはダメだ」みたいな論調をどこかで見かけたことはあると思います

Reactやvueをそのためだけに入れるのは大げさ

これらが悪いとは思いませんが、こういった「ほんの少しだけ拡張する」ような要素のためにreactやvueなどの大きなフレームワークを入れるのは学習コストも大きく負担になりやすいです

そして、これらはあくまでも「js上でviewを組み立てる」という仕組みのため「gon」などでRails側から無理やり値を渡してやる必要があり、Railsとの結合性が良いとは言えません(値を渡すしんどさはjqueryと変わらない)

そこでDHHが作ったstimulus.jsに手を出そう

DHH(Railsの作者)が作って、javan(turbolinksの作者)に仕上げてもらったのが始まり(らしい)stimulus.jsですが、日本での知名度はイマイチ……どころか「チュートリアルをやってみました!」以上の記事が3件か4件しかないというくらい存在を認知されていないフレームワークです

知名度が低いと言ってもgithubでは9.5kスターありますしちゃんと海外では利用実績もあるのでそのあたりはご安心下さい
https://github.com/stimulusjs/stimulus/

ちょうど2週間前にv2.0がリリースされたのでしばらくは大きな変更もないでしょうしこのあたりでみなさんも導入してみませんか?という事で長い前置きになりましたが以下本題です

stimulus.jsのアプローチは「HTMLに寄り添う」

さっきちょっと書きましたが「react」や「vue」のアプローチは「jsでviewを全て出力する」というものです

従ってどうにかしてjs側に値を渡す必要があり、大抵の場合はAPIを作ってjsonでやり取りして組み立てると思うのですが「ほんのちょっと非同期のフォローボタンを入れたいだけ」のためにわざわざ導入するのは負担が大きいことでしょう

従ってjQueryなどで、Railsデフォルトのlink_to remote: true (= data-remote)あたりで投げて.on('ajax:success')にフックしてviewを書き換える〜なんて言うやりかたをしている人が多いと思います

stimlus.jsのアプローチはそれと全く一緒です

Railsによって生成されたHTMLに作用する

例えば以下のようなコードを考えてみましょう

<%= link_to follow_path(@user), remote: true, id: "follow-user-#{@user.id}" do %>
フォローする
<%= end %>
<script>
  $(document).ready({
    $("#follow-user-<%= @user.id %>").on('ajax:success', function(e){
      var result e.detail[0]
      $(this).html(result.html)
    })
  })
</script>

フォローをして、サーバー側からその部分のHTMLを返して書き換えるというよくあるシンプルなフォローボタンです

実際にはこんな感じでHTMLファイルの中にjavascriptを書かずに、follow.jsなどのファイルを作って、以下のように汎用性の高い形で書き換える事が多いでしょう

<%= link_to follow_path(@user), remote: true, class: 'js-follow-button' do %>
フォローする
<%= end %>
  $(document).ready({
    $(".js-follow-button").on('ajax:success', function(e){
      var result e.detail[0]
      $(this).html(result.html)
    })
  })
</script>

悪くはない、悪くはないのですが、無理やり頑張ってる感がすごいですし、「jsに値を渡すためだけのclassやid」が増えていきHTMLファイル自体の見通しも悪くなります

またjsファイルへの書き出しが増えるに連れてどんどんjsファイル全体の見通しも悪くなり、そのうち「使ってるのか使ってないのかわからないぐちゃぐちゃなjsファイルの山」が出来上がりどんどん負債が積み重なっていきます

stimulus.jsで書き換えると

<%= link_to follow_path(@user), remote: true, data-controller: 'follow-button' do %>
フォローする
<%= end %>

※js側は省略

stimulus.jsではこんな感じで「data-controller」というものを指定することで、js側と自動で結びついてくれます

これだけだと「classで結びついていたのがdata-controllerになっただけでは?」と感じるかもしれませんが、当然他にも嬉しいことがいくつかあって……jQueryでやっていた「オブジェクトを渡す」「値を渡す」「アクションを起こす」の3つをjqueryよりも見通しよく、すっきりキレイに書けるというのがstimulus.jsのメリットです