編集機能と削除機能の実装
残る処理は、編集機能と削除機能です。一覧ページには[Show this word]リンクがあるのみなので、編集、削除するにはページ遷移が必要になってしまいます。SPAらしく、一覧ページで編集と削除もできるようにするために、[Show this word]リンクの替わりに[Edit this word]リンクと[Destroy this word]ボタンを置きます。また、一覧の各項目を操作可能にするために、一覧ページの各項目をフレームで囲みます。
<div id="words">
<% @words.each do |word| %>
<%# フレームで囲む %>
<%= turbo_frame_tag word do %>
<%= render word %>
<p>
<%# 編集リンクと削除ボタンを置く %>
<%= link_to "Edit this word", edit_word_path(word) %> |
<%= button_to "Destroy this word", word, method: :delete %>
</p>
<% end %>
<% end %>
</div>
項目をフレームで囲ったので、編集フォームでの置き換えができるようになります。そこで、編集フォームであるedit.html.erbをリストのようにフレームで囲みます。また、[Show this word]リンクは意味がないので削除してしまいます。
<%# フレームで囲む %>
<%= turbo_frame_tag @word do %>
<%= render "form", word: @word %>
<br>
<div>
<%# 元に戻るリンクだけを置く %>
<%= link_to "Back to words", words_path %>
</div>
<% end %>
turbo_frame_tagメソッドの引数にモデルオブジェクトを与えていますので、id属性が一覧側と一致するようになります(図3)。
この時点ではフォームに置き換わるだけなので、更新と削除でStreamsアクションを返すように、コントローラのupdateアクションメソッドとdeleteアクションメソッドをそれぞれリストのように変更します。
def update
if @word.update(word_params)
# showビューをレンダリングして返す
render :show
else
…略…
end
def destroy
@word.destroy
# 削除メソッドの呼び出しをレンダリングして返す
render turbo_stream: turbo_stream.remove(@word)
end
updateメソッドでは、更新に成功したらshowビュー(show.html.erb)をレンダリングして返すようになっています(本来は詳細ページであるshowビューである必要はないのですが、簡略化のためこのようにしています)。turbo_frame_tagメソッドの引数の@wordによって項目固有のid属性となるので、編集された項目のフレームがこの内容によって更新されます。[Back to words]リンクは意味がなく、一覧ページのスタイルに合わせるために削除しています。
<%# フレームで囲む %>
<%= turbo_frame_tag @word do %>
<%= render @word %>
<div>
<%= link_to "Edit this word", edit_word_path(@word) %> |
<%= button_to "Destroy this word", @word, method: :delete %>
</div>
<% end %>
destroyメソッドでは、削除後に「turbo_stream: turbo_stream.remove(@word)」をレンダリングして返すようになっています。これは、コンテンツタイプをTurbo Streamとして返すためのショートカットで、内容は「turbo_stream.remove(@word)」となります。これにより、削除した項目が一覧ページからも削除されます(図5)。
