3

I have a controller action where I'd like to receive form data, execute some business logic, then refresh the form. This works Ok if I save the object in the database then use a redirect_to. I would prefer the controller edit the object in memory and render the response directly.

For example, take a standard rails 5.1.4 generated app generated like so:

rails new turbolinks_example
rails g scaffold Thing name
rails db:migrate

The form, slightly edited for brevity and to enable turbolinks:

<%= form_with(model: thing) do |form| %>
  <div class="field">
    <%= form.label :name %>
    <%= form.text_field :name, id: :thing_name %>
  </div>

  <div class="actions">
    <%= form.submit %>
  </div>
<% end %>

A) Now we edit the controller to change the object. This uses a redirect to edit and works:

ThingsController < ApplicationController
...
  def update
    if @thing.update(thing_params)
      @thing.update name: "#{@thing.name} is OK"
      redirect_to edit_thing_path(@thing)
    end
  end 

B) This uses a render and does not work:

class ThingsController < ApplicationController
  ...
  def update
      if @thing.update(thing_params)
        @thing.name = "#{@thing.name} is OK"
        render :edit
      end
  end
end

With A) - Update request is received by controller - Object is modified (& saved) - Redirect is returned - Rediredted url is rendered - DOM is updated With B) - Update request is received by controller - Object is modified (in memory) - Response is rendered - Response is received by browser, but ignored

The response received, looks correct. Full HTML, with the changes made to the object. How do I get turbolinks to notice it and replace document.body like normal?

The full project, including development.log is on Github

Jacob Vanus
  • 534
  • 4
  • 13

1 Answers1

3

The problem is that, in Rails 5:

  • Forms are remote by default: they are sent via AJAX unless local: true provided
  • When rendering HTML as a response to an AJAX call, nothing happens unless, of course, there is custom javascript in the client handling the response
  • Turbolinks is enabled by default, which handles redirect_to properly, but does nothing for render

I think this is an inconsistency in Rails that causes much confusion, such as the problem you exposed with your code. I created a gem turbolinks_render to deal with this problem. I also wrote a little post on this very same problem.

I hope that, one way or other, this gets fixed in future Rails versions.

jmanrubia
  • 1,865
  • 20
  • 13
  • I installed your gem hoping it would allow my form to submit. But the form still doesn't submit. The form only works when the link_to the page with the form is given `data: { turbolinks: false }` . Ideally I would like to keep turbolinks on. Could your gem fix this? There are a lot of posts about forms not submitting due to turbolinks (and the only successful way of dealing with this for me has been to turn turbolinks off) – stevec Jul 05 '18 at 01:55
  • There is probably something wrong in your code. What do you mean by "the form doesn't submit"? You need `//=require rails-ujs` in your `application.js` to make remote works forms (for Rails >= 5.1), or use `jquery-ujs` for previous versions. Maybe you are missing that and remote forms are not working because of that. If you can share some code I can try to help. – jmanrubia Jul 05 '18 at 08:07
  • I tried adding `//=require rails-ujs` to `application.js` but it didn't change anything (form still didn't work). [here](https://stackoverflow.com/questions/19365809/form-submit-button-only-works-after-reload/51212406#51212406) are many others experiencing a similar problem. I found a work around using the answer provided by carlosveucv but I believe that is simply turning off turbolinks rather than addressing whatever is causing the issue. I agree that rails needs to address this. But if that's not happening, making a gem that does could be a great interim solution – stevec Jul 06 '18 at 14:35