I'm kinda following the rails tutorial to learn it and I wanted to learn with turbo.
This is my index.html.erb view:
<%= turbo_include_tags %>
<h1>Notes</h1>
<turbo-frame id="new_note">
<%= form_with(model: Note.new, url: notes_path) do |form| %>
<div>
<%= form.label :content %>
<%= form.text_area :content %>
</div>
<%= form.submit "Create Note" %>
<% end %>
</turbo-frame>
<turbo-frame id="notes">
<div>
<% @notes.each do |note| %>
<div>
<p><span><%= note.id %></span><%= note.content %></p>
<small> <%= note.created_at %> </small>
<%= link_to "Destroy", note_path(note), data: { turbo_method: :delete } %>
</div>
<% end %>
<%= link_to "New note", new_note_path %>
</div>
</turbo-frame>
My _list.html.erb template:
<% notes.each do |note| %>
<div>
<p><span><%= note.id %></span><%= note.content %></p>
<small> <%= note.created_at %> </small>
<%= link_to "Destroy", note_path(note), data: { turbo_method: :delete } %>
</div>
<% end %>
And this is my controller:
def index
@notes = Note.all.order(created_at: :desc)
end
...
def new
@note = Note.new
end
def create
@note = Note.new(note_params)
if @note.save
@notes = Note.all # Reload all notes or fetch them as needed
respond_to do |format|
format.turbo_stream do
render turbo_stream: turbo_stream.replace("notes", partial: "notes/list", locals: { notes: @notes })
end
format.html { redirect_to notes_url } # Fallback in case JavaScript is disabled
end
else
render :new
end
end
...
I want when clicking on the submit button to create a new note and update the list. I have two issues in my code. The first one is after the validation the form is not clean. I don't know the best way to do it.
The second one is to refresh the list. It works only one time after the first time I click on the submit button. I cannot create a second note without refreshing the page. Another issue is that the new note is added at the end of the list instead of the beginning (because my list is sorted by created_at value).
You to turbo_stream.update
instead of turbo_stream.replace
, when you replace
you're loosing <turbo-frame id="notes">
which means it doesn't work the second time:
render turbo_stream: turbo_stream.update("notes", partial: "notes/list", locals: { notes: @notes })
<%= turbo_include_tags %>
is a deprecated helper and should not be used.
You don't have to re-render the entire list again. Only add the newly created note to the list:
<!-- app/views/notes/index.html.erb -->
<div id="new_note">
<%= render "form", note: Note.new %>
</div>
<div id="notes">
<%= render @notes %>
</div>
<!-- app/views/notes/_note.html.erb -->
<div id="<%= dom_id note %>">
<%= note.content %>
</div>
# app/controller/notes_controller.rb
def create
@note = Note.new(note_params)
respond_to do |format|
if @note.save
format.turbo_stream do
render turbo_stream: [
turbo_stream.update(:new_note, partial: "notes/form", locals: {note: Note.new}),
turbo_stream.prepend(:notes, @note),
]
end
format.html { redirect_to notes_url(@note), notice: "Note was successfully created." }
else
format.turbo_stream do
render turbo_stream: [
turbo_stream.update(:new_note, partial: "notes/form", locals: {note: @note}),
]
end
format.html { render :new, status: :unprocessable_entity }
end
end
end