createアクションがStreamsアクションを返すようにする
新規作成フォームからはcreateアクションが呼び出されるので、コントローラのcreateアクションメソッドの内容を以下のように変更します。
…略… if @user.save # createビューのレンダリングに変更 render :create else …略…
saveメソッドでの保存に成功したら、詳細ページへリダイレクトするのではなく、createビューをレンダリングした結果を返すということにします。ここでのcreateビューは、Streamsのタグを返すビューです。app/views/words/create.turbo_stream.erbをリストの内容で作成します。
<%# 作成した項目を一覧に挿入するStreamsアクション %> <%= turbo_stream.append 'words' do %> <%= render @word %> <p> <%= link_to "Show this word", @word %> </p> <% end %> <%# フォームをリンクで置き換えるStreamsアクション %> <%= turbo_stream.update 'new_word' do %> <%= link_to "New word", new_word_path %> <% end %>
ビューのファイル名をcreate.turbo_stream.erbとしているのは、返すのが単なるHTMLドキュメントではなく、Streamsドキュメントとするためです。create.html.erbというファイル名では正しく動作しません。
そしてここで登場するのが、turbo-railsライブラリのヘルパーである2つのメソッドです。
- turbo_stream.appendメソッド:引数で指定されるid属性を持つ要素の末尾にブロックの内容を挿入する
- turbo_stream.updateメソッド:引数で指定されるid属性を持つ要素の内部をブロックの内容で置き換える
前者では、引数に「words」を指定していますので、index.html.erbにある<div id="words">~</div>の末尾に、新規作成した項目がリンクとともに挿入されます。後者では、引数に「new_word」を指定していますので、<turbo-frame id="new_word">~</turbo-frame>の内部をリンクに置き換えます。
[NOTE]挿入、置換のためのその他のヘルパーメソッド
ここではturbo_stream.appendメソッドとturbo_stream.updateメソッドを用いましたが、要素先頭に挿入するturbo_stream.prependメソッド、要素の内部ではなく要素そのものを置き換えるturbo_stream.replaceメソッドもあります。
[NOTE]turbo_stream.xxxxメソッドのレンダリング
turbo_stream.xxxxメソッドはturbo-streamタグを生成しますが、具体的なレンダリングのイメージは以下の通りです(turbo_stream.appendメソッドの場合)。メソッドの種類はaction属性に置き換えられ、対象のid属性はtarget属性で指定されます。
<turbo-stream action="append" target="new_word"> …挿入する内容… </turbo-stream>
Streamsの動作
これでアプリケーションを動作させてみると、[Create Word]ボタンのクリックで追加した項目が一覧の最後に現れ、[New word]リンクも復活することが分かります(図1)。
内部で何が行われているかを以下にまとめてみました(図2)。
- [Create Word]ボタンのクリックでコントローラのcreateアクションへのfetchリクエストが発生
- saveメソッドでの保存が成功すれば、createビュー(create.turbo_stream.erb)をレンダリングして返す
- createビューの中身は2つのStreamsアクションであり、それぞれ追加項目の挿入、[New word]リンクの復元を行う
Streamsアクションによる更新では、Framesによるフレームだけでなく、一般的なHTML要素も操作の対象になることがお分かりいただけると思います。