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

Latest comments (7)

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
 
matiascarpintini profile image
Matias Carpintini

Thank you!

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!