In a new Rails 7 application, I’m working on an autosave feature for a form with just a textarea. I use custom JavaScript to handle the form submission, and this works well.
window.addEventListener("load", function () {
const form = document.querySelector(".form");
const field = document.querySelector(".field");
if (!form || !field) return;
let submitTimeout;
field.addEventListener("input", () => {
clearTimeout(submitTimeout);
submitTimeout = setTimeout(() => {
form.submit();
}, 500);
});
});
The ERB form is as follows (the @resource variable is always a persisted record, since it’s set up that way in the edit action):
<%= form_with scope: :resource, model: @resource, remote: true, class: "form" do |form| %>
<%= form.hidden_field :id %>
<%= form.text_area :text, size: "30x10", class: "field" %>
<% end %>
However, when the form is submitted (behind the scenes), it calls the update action in my controller, which looks like so:
class ResourcesController < ApplicationController
...
def update
resource = current_user.resources.find(resource_params.delete(:id))
resource.update!(resource_params)
end
private
...
end
and this works well in most browsers, except when it comes to Safari. In Safari, the lack of response from this action confuses the browser and it shows a download link, which isn’t the desired behaviour.
To get around this, I thought it would be useful to return some JavaScript, which I’ve seen elsewhere (on StackOverflow), so I updated the controller to respond to js and updated the form to use the js request format type:
<%= form_with scope: :resource, model: @resource, remote: true, format: :js, class: "form" do |form| %>
<%= form.hidden_field :id %>
<%= form.text_area :text, size: "30x10", class: "field" %>
<% end %>
class ResourcesController < ApplicationController
...
def update
resource = current_user.resources.find(resource_params.delete(:id))
resource.update!(resource_params)
respond_to do |format|
format.js
end
end
private
...
end
and I created a sample JS file to test this setup in /views/resources/update.js.erb:
console.log("hello world");
The issue is that after the response comes back, the browser redirects to /resources/:id.js where :id is the ID of the persisted resource. This is not the desired behaviour and not what I expected based on other questions and answers I’ve seen here. My intenteion, of course, is that the JavaScript is executed on the page. I figure it worked in older versions, but not in Rails 7. I’m on Rails 7.0.5, to be precise.