How to upgrade from Turbolinks to Hotwire & Turbo Discussion
Hey Chris, thanks for going over Turbo and StimulusJS 2.0 changes, I'm really excited about using them in my projects!
One really big thing that would be great to cover is using dialogs/modals with Turbo.
In several of my projects, users really like having dialogs/modals that can show information or allow them to edit information via forms without losing context in the app.
One issue with that, however, is that you can't bookmark or link to a "show" action dialog because it's displayed via JS. In my case, I can have multiple dialogs on top of each other, and each dialog is dynamically appended to the body, which is different from the approach of having a single <div id="dialog">...</div>
hidden on the page and just updating content (because you can't have multiple).
With regards to dialogs and forms, I've gone the route of remote: true
on all the forms and using create.js.erb
to execute JS code on the client. As an example:
# posts_controller.rb
def create
@post = Post.new(post_params)
if @post.save
# create.js.erb
else
render :form_validation_error # js.erb file
end
end
# posts/create.js.erb
Dialog.hide("#new-post-form")
Snackbar.create("Post successfully created")
# posts/form_validation_error.js.erb
# Using jQuery syntax for example of what I'm doing
$("#new-post-form .dialog-content").replaceWith("<%=j render(partial: 'posts/form') %>")
I've been looking at Turbo with its turbo-forms and turbo-streams, and it looks like the core team is headed in a different direction, since they don't want to execute arbitrary JS as a response anymore and instead recommend StimulusJS callbacks (read that in one of the guides for either StimulusJS or Turbo, can't remember which).
But the core issue is making Turbo play nicely with multiple dialogs/modals on a page, some of them just showing info and some of them actually forms that submit data.
My current solutions "work", but it looks like I'll need to do a significant amount of refactoring to make them play nicely with the direction Turbo is going.
I am using the most recent versions of hotwire and turbo rails but when submitting a form (successfully) nothing happens. If there is an error it displays the error. Anyone an idea what could go wrong there?
Updating my Ruby version to 2.6.5 and updating turbo-rails to 0.5.3 resolved this issue for me.
I'm having the same issue...
ruby: 2.7.2
rails: 6.1
turbo-rails: 0.5.3 (7.0.0-beta.3)
I'm using the turbo_frame_tag 'report_form'
wrapping the form and in the controller I have
def create
@report = Report.new(report_params)
respond_to do |format|
if @report.save
format.html { redirect_to @report, notice: "Report was successfully created" }
format.json { render :show, status: :created, location: @report }
else
# format.turbo_stream { render turbo_stream: turbo_stream.replace(@report, partial: 'reports/form', locals: { report: @report })}
format.html { render :new, status: :unprocessable_entity }
format.json { render json: @report.errors, status: :unprocessable_entity }
end
end
end
The commented line also works, in that case, the response for the error only renders the form
partial, but I still have the same problem for the success... nothing happens.
I seem to have an issue getting successful submissions to work in this use case.
For example, I have a form like:
<%= turbo_frame_tag record do %>
<%= form_with model: record, local: true) do |form| %>
<%# ... %>
<% end %>
<% end %>
If the controller action is:
def update
if @record.update(record_params)
redirect_to record, notice: 'Record was successfully updated!'
else
render :edit
end
end
(Note that I don't have responders in my actions because I'm creating another separate JSON API, but maybe I need to create one for turbo streams now?)
I see the error messages as expected when there is a validation error, however I do not get redirected to the :show
action when the form successfully submits. From looking here it kinda seems like this isn't supported, but it seems like the idiom up until now for Rails, so I'm not sure if I'm reading this correctly. Any tips?
Thanks!
For now I am simply removing the turbo_frame_tag
and returning a status: :unprocessable_entity
on error which causes Turbo to work in the success and error case, although it does re-render the whole page. It seems to work fine, although I am a bit curious if there's a more complete solution to this.
I just upgraded to Hotwire/Turbo today and am in the same situation. Still learning the ropes with Turbo, but it does seem wrapping forms with turbo frame tags in existing applications is generally not a workable solution.
Hi everyone, in application.html.erb, should our stylesheet and script pack tags be annotated with 'data-turbo-track': 'reload' or 'data-turbolinks-track': 'reload' after switching to hotwire/turbo?
I'm wondering if adopting Hotwire means the end of webpacker in my Rails application, as webpacker is pretty heavy lifting considering the scant js I use. So is it back to the asset pipeline and precompiling and all that? Maybe a tutorial on dismantling webpacker safely and installing hotwire in its place. There doesn't seem to be anyone clearly stating that webpacker is on the chopping block. Will you make that call, Chris?
Hotwire is not a replacement for Webpacker but there are other gems which could replace webpacker in your project, depending on how you're using it. https://gorails.com/episodes/esbuild-jsbundling-rails
Hi everyone!
I've managed to get forms working using status: :unprocessable_entity
against my calls to render
for error cases.
However, some of my form pages are long, and so while the flash messages are correctly displayed when the page re-renders, they are off screen at the top. With Turbolinks, the pages would naturally reload at the top of the page.
Anybody know the best way to handle this case?
Thank you!