Rails 7.1.3.2
turbo-rails 2.0.5 (i.e. Turbo 8)
I have an index page showing a list of records and I want it to have a form for adding new records which refreshes/morphs the page when records are created.
I have got it working but my implementation feels suboptimal, as if I have missed something. Any feedback would be much appreciated
My index page renders the records as normal:
<%= render @posts %>
I have an âAdd postâ link which shows the post form:
<%= link_to 'Add post', new_post_path %>
To make the form replace the âAdd postâ link, I wrap them both in the same turbo frame:
<!-- /posts/index.html.erb -->
<%= turbo_frame_tag :new_post do %>
<%= link_to 'Add post', new_post_path %>
<% end %>
<!-- /posts/new.html.erb -->
<%= turbo_frame_tag :new_post do %>
<%= form_with model: @post do |f| %>
<%= f.text_field :title %>
<%= f.submit %>
<% end%>
<% end %>
Next I want an invalid form submission to render the form with validation errors inside the turbo frame:
# app/controllers/posts_controller.rb
def create
@post = Post.new(post_params)
if @post.save
# TODO
else
render :new, status: :unprocessable_entity
end
end
This works. Next I want a valid form submission to refresh the index page, showing the new post, removing the form, and adding the âAdd postâ button again.
I tried redirecting to the index page:
# app/controllers/posts_controller.rb
def create
@post = Post.new(post_params)
if @post.save
redirect_to posts_path
else
render :new, status: :unprocessable_entity
end
end
This of course simply updates the turbo frame: removing the form and adding the âAdd postâ button. It doesnât refresh the list of posts.
Next I tried getting the form to target the whole page, so that a valid form submission would break out of the turbo frame when redirecting, allowing morphing to work:
<!-- /posts/new.html.erb -->
<%= turbo_frame_tag :new_post do %>
<%= form_with model: @post, data: {turbo_frame: "_top"} do |f| %>
<%= f.text_field :title %>
<%= f.submit %>
<% end%>
<% end %>
This works for valid form submissions â but breaks for invalid form submissions: the invalid form with validation errors is rendered on a new page. Somehow despite render :new, status: :unprocessable_entity
, the response breaks out of the turbo frame. I didnât think that was supposed to happen. Can anyone explain this to me please?
So I removed the data: {turbo_frame: "_top"}
from the form and found a way to break out of the frame from the server:
# app/controllers/posts_controller.rb
def create
@post = Post.new(post_params)
if @post.save
render turbo_stream: turbo_stream.action(:refresh, '_top')
else
render :new, status: :unprocessable_entity
end
end
Now this does everything I want. But it feels wrong to have to resort to a turbo stream response to force the refresh. Can anyone show me a better way please?
Finally I should mention that my model is broadcasting refreshes, and the index page is listening to those broadcasts.
# app/models/post.rb
class Post < ApplicationRecord
broadcasts
end
<!-- posts/index.html.erb -->
<%= turbo_stream_from @post %>
I can see this working when I update a post in the Rails console, and the page automatically refreshes.
However it doesnât help my form situation. I think thatâs because broadcasts caused by your own requests are discarded, as far as I understand?
Anyway, I would greatly appreciate any help!