🦓
[Rails]turboによる非同期インライン編集
はじめに
インライン編集は、ページ上の特定の要素(タイトルなど)をクリックすると、その要素が編集モード(フォーム)に切り替わり、テキストを直接編集できるようになります。
フォーム全体の読み込みと送信より素早くにデータを更新でき、UXの向上につながります。
環境
Rails 7.0.7
ruby 3.2.1
tl;dr
ProjectのMVCを作成されていることを前提で進めていきます。
-
turbo_frame
を用意する - フォーム内に切り替わる要素を同じ
id
で指定する - 編集、送信、キャンセルボタンを用意する
- コントローラーでturboのレスポンスを有効する
- 非同期更新用パーシャルを作成する
- 編集、送信、キャンセルボタンを非表示にする
- 再利用性を向上する
turbo_frame
を用意する
フォームを送信できるようにform_with
ヘルパータグを使います。
編集ボタンを追加します。
app/views/projects/_project.html.erb
<% frame_id = dom_id(project, "title") %>
<%= form_with model: project, data: { turbo_frame: frame_id } do |form| %>
<%= turbo_frame_tag frame_id do %>
<%= project.title %>
<%= link_to '編集', edit_polymorphic_path(project) %>
<% end %>
<% end %>
id
で指定する
フォーム内に切り替わる要素を同じタイトルをクリックしたらフォームに切り替えたいので、タイトルとフォームに同じid
をつけます。
また、送信ボタンとキャンセルボタンも用意します。
app/views/projects/_form.html.erb
<% frame_id = dom_id(@project, "title") %>
<%= turbo_frame_tag frame_id do %>
<%= form.text_field :title%>
<%= form.submit %>
<%= link_to 'キャンセル','' %>
<% end %>
コントローラーでturboのレスポンスを有効する
app/controllers/projects_controller.rb
class ProjectsController < ApplciationController
def update
respond_to do |format|
if @project.update(project_params)
format.turbo_stream
else
...
end
end
end
end
非同期更新用パーシャルを作成する
タイトルを更新されたら元の表示に戻したいのでパーシャルを作成します。
app/views/projects/update.turbo_stream.erb
<% frame_id = dom_id(project, "title") %>
<%= form_with model: project, data: { turbo_frame: frame_id } do |form| %>
<%= turbo_frame_tag frame_id do %>
<%= project.title %>
<%= link_to 'edit', edit_polymorphic_path(project) %>
<% end %>
<% end %>
編集、送信、キャンセルボタンを非表示にする
投稿全体を編集する場合、タイトルの横にあるボタン達をCSSで非表示にしましょう。
.inline-btn {
display: none;
}
.inline-edit .inline-btn {
display: initial;
}
再利用性を向上する
他の要素にもインライン編集を効かせた方が良いので、_inline_edit.html.erb
パーシャルを作成します。
属性をattribute
に渡します。
app/views/projects/_inline_edit.html.erb
<% frame_id = dom_id(model, "#{attribute}") %>
<%= form_with model: model, data: { turbo_frame: frame_id } do |form| %>
<%= turbo_frame_tag frame_id, class: 'inline-edit' do %>
<%= yield %>
<%= link_to '編集', edit_polymorphic_path(model) %>
<% end %>
<% end %>
パーシャルを読み込みます。
app/views/projects/_project.html.erb
<%= render 'projects/inline_edits', model: project, attribute: :title do %>
<%= project.title %>
<% end %>
フォーム内のturbo_frame
もパーシャル化します。
app/views/projects/_inline_fields.html.erb
<% frame_id = dom_id(form.object, "#{attribute}") %>
<%= turbo_frame_tag frame_id do %>
<%= yield %>
<%= form.submit %>
<%= link_to 'キャンセル','' %>
</div>
<% end %>
フォームに読み込みます。
app/views/projects/_form.html.erb
<%= render 'projects/inline_fields', form: form, attribute: :title do%>
<%= project.title %>
<% end %>
非同期更新用のパーシャルにも反映させます。
app/views/projects/update.turbo_stream.erb
<% frame_id = dom_id(@project, "title") %>
<%= turbo_stream.replace frame_id do%>
<%= render 'projects/inline_edits', model: @project, attribute: :title do %>
<%= project.title %>
<% end %>
<% end %>
終わりに
他のサイトでよく見かけるインライン編集を実装できて良かったです!
参考したリポジトリ
Discussion