Rails turbolinks break submit remote form

Tom Naessens picture Tom Naessens · Mar 9, 2014 · Viewed 8.6k times · Source

I'm having a rather weird problem using Rails 4, Turbolinks and a remote form. I have a form looking like:

<%= form_for [object], remote: true do |f| %>                                                   
    <td><%= f.text_field :name, class: 'form-control' %></td>                                     
    <td><%= f.email_field :email, class: 'form-control' %></td>                                   
    <td><%= f.submit button_name, class: 'btn btn-sm btn-primary' %></td>
<% end %>    

This form adds (creates) a new object. It does however not always work:

  • When I load the page directly using the URL or a refresh; it works
  • When I navigate from my app to this page; it fails

When disabling Turbolinks for this link, the page worked perfectly.

I have two questions:

  1. Why doesn't this work? Is this because the remote handlers aren't attached to the button because of a JQuery/Turbolinks problem?
  2. How can I work around this problem?

Thanks in advance.

Solution

Thanks to @rich-peck, the solution was to add a piece of javascript that manually submits the form upon clicking the button:

<%= javascript_tag do %>
  var id = "#<%= dom_id(f.object) %>";
  var inputs = $(id).parent().find('input');
  console.log(inputs);
  $(id).parent().find('button').on('click', function(e) {
    e.preventDefault();
    $(id).append(inputs.clone());
    $(id).submit();
  });
<% end %>

This code adds javascript to the form table row, getting the inputs, appending them to the ID and submitting the form. The preventDefault(); prevents the query from getting sent twice when the page is refreshed and the form actually works.

Answer

Richard Peck picture Richard Peck · Mar 9, 2014

Turbolinks

As mentioned, the problem with Turbolinks is that it reloads the <body> part of the DOM with an ajax call - meaning JS is not reloaded, as it's in the head

The typical way around this issue is to delegate your JS from the document, like this:

$(document).on("click", "#your_element", function() {
    //your code here
});

Because document is always going to be present, it will trigger the JS continuously


Remote

With your issue, it's slightly more tricky

The problem is you're relying on the JQuery UJS (unobtrusive JavaScript) engine of Rails, which is difficult to remedy on its own

We've never had this issue & we use Turbolinks all the time - so I suppose the problem could be with how you're constructing your form / handling the request. This GitHub seemed to recreate the issue, and it was to do with the table

Maybe you could try:

<%= form_for [object], remote: true do |f| %>                                                   
    <%= f.text_field :name, class: 'form-control' %>                                     
    <%= f.email_field :email, class: 'form-control' %>                              
    <%= f.submit button_name, class: 'btn btn-sm btn-primary' %>
<% end %>