DEV Community

thomasvanholder
thomasvanholder

Posted on

How to migrate Rails UJS to Hotwire (Turbo)

See Hotwire handbook

  1. Update hotwired/turbo-rails
  2. Remove rails/ujs
  3. Replace link_to delete
  4. Replace link_to data confirm
  5. Replace button data disable with
  6. Set status response in controller

1. Update hotwired/turbo-rails

In package.json, update @hotwired/turbo-rails package to 7.1.0 (or greater)

 "@hotwired/turbo-rails": "^7.1.0"
Enter fullscreen mode Exit fullscreen mode

2. Remove rails/ujs

  • From the package.json file
yarn remove @rails/ujs
Enter fullscreen mode Exit fullscreen mode
  • From the application.js entry point
require("@rails/ujs").start() // remove this line
Enter fullscreen mode Exit fullscreen mode

3. Replace link_to delete

method: :delete
becomes
data: {turbo_method: :delete}

<%# Old %>
<% link_to "Destroy", task_path(@task), method: :delete %>

<%# New %>
<% link_to "Destroy", task_path(@task), data: {turbo_method: :delete} %>
Enter fullscreen mode Exit fullscreen mode

4. Replace link_to data confirm

data: {confirm: 'Are you sure?'}
becomes
data: {turbo_confirm: 'Are you sure?'}

<%# Old %>
<% link_to "Destroy", task_path(@task), method: :delete, data: {confirm: 'Are you sure?'} %>

<%# New %>
<% link_to "Destroy", task_path(@task), data: {turbo_method: :delete, turbo_confirm: 'Are you sure?'} %>
Enter fullscreen mode Exit fullscreen mode

5. Replace button data disable with

In Rails UJS, a form's submit button can be disabled and its text replaced by adding the data disable_with attribute.

<%= f.button "Search", data: { disable_with: "Searching..."} %>
Enter fullscreen mode Exit fullscreen mode

With Turbo, you can set the text content based on the parent's button disabled status. Source

button             .show-when-disabled { display: none; }
button[disabled]   .show-when-disabled { display: initial; }

button             .show-when-enabled { display: initial; }
button[disabled    .show-when-enabled { display: none; }
Enter fullscreen mode Exit fullscreen mode
<button>
  <span class="show-when-enabled">Submit</span>
  <span class="show-when-disabled">Submitting...</span>
</button>
Enter fullscreen mode Exit fullscreen mode

Or if you use Tailwind, you can leverage Tailwind's group and disabled status to create a similar effect.

<%= f.button class: "group" do %>
   <span class="group-disabled:hidden">Search</span>
   <span class="hidden group-disabled:block group-disabled:cursor-wait">Searching...</span>
<% end %>
Enter fullscreen mode Exit fullscreen mode

6. Set status response in controller

Respond with a 303 status code

class TasksController
 ...

  def destroy
    @task = Task.find(params[:id])
    @task.destroy
    redirect_to tasks_path, info: "Task deleted", status: :see_other
  end 
end
Enter fullscreen mode Exit fullscreen mode

Top comments (7)

Collapse
 
matiascarpintini profile image
Matias Carpintini

Thank you!

Collapse
 
bakivernes profile image
Vernes Pendić

Hi Thomas! I'm having issues with: link_to, url, method: :get. The link goes to a controller action that response with turbo_stream but the request arrives as HTML and I get an error after removing ujs. Tried adding data-turbo-method="get" but because my link is inside a turbo-frame it says Response has no matching <turbo-frame id="idOfRandomParent"> element. Did you by any chance encounter such issues?

Collapse
 
thomasvanholder profile image
thomasvanholder

@bakivernes, you can break out a turbo_frame by specifing the target attribute on a link.

link_to 'root', root_path, target:"_top"
# alternative
link_to 'root', root_path, data: { turbo_frame: '_top' }
Enter fullscreen mode Exit fullscreen mode

See also here

Collapse
 
fcatuhe profile image
François Catuhe

Excellent, that sums up what I also discovered.

Have you investigated the replacements for Rails.fire and Rails.ajax? Asking as these are the 2 next on my list.

Collapse
 
thomasvanholder profile image
thomasvanholder

@fcatuhe, I'm glad you find it useful.

There is a recent rails library called Request.js which can fetch URL's in JS. This can help migrate existing Rails.fire and Rails.ajax calls.

Collapse
 
fcatuhe profile image
François Catuhe

Wow I had missed that one, that's exactly it, thanks!

Collapse
 
superails profile image
Yaroslav Shmarov

very good write-up on removing ujs! thanks!