Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails responding to Javascript request even though format.js is not on controller

In a standard, scaffolded Rails 5.1 (or 5.0) controller, you get this on the create action:

def create
    @test = Test.new(test_params)

    respond_to do |format|
      if @test.save
        format.html { redirect_to @test, notice: 'Test was successfully created.' }
        format.json { render :show, status: :created, location: @test }
      else
        format.html { render :new }
        format.json { render json: @test.errors, status: :unprocessable_entity }
      end
    end
  end

As you see, there is no format.js there.

But if you add remote: true to the form (or, in Rails 5.1, you remove the local: true which will use the new default which is to post via ajax), the form works: the browser will send a post via xhr and redirect to the newly created record.

Looking at dev tools, I see that the response for the form submission was a 200 OK with the following content:

Turbolinks.clearCache()
Turbolinks.visit("http://localhost:3000/tests/10", {"action":"replace"})

Console also indicates it was processed by Javascript: Started POST "/tests" for 127.0.0.1 at 2017-06-18 09:38:25 -0300 Processing by TestsController#create as JS

The question is then: how is Rails handling this response/redirect for the JS request if there's no format.js in the controller?

I'm all in for Rails magic but I want to know how this works, and I haven't seen this 'fallback the JS request to the format.html block' documented anywhere.

like image 946
sandre89 Avatar asked Jun 26 '26 20:06

sandre89


1 Answers

It looks like the code that is generating that response comes from the turbolinks-rails gem.

https://github.com/turbolinks/turbolinks-rails/blob/v5.0.1/lib/turbolinks/redirection.rb#L14

From the linked code it looks like turbolinks prepares a js response when redirect_to is called, the request is XHR, not a GET request, and turbolinks: false was not provided to the redirect_to call.

Turbolinks overrides ActionController redirect_to when the gem is present and app.config.turbolinks.auto_include is truthy.

def redirect_to(url = {}, options = {})
  turbolinks = options.delete(:turbolinks)

  super.tap do
    if turbolinks != false && request.xhr? && !request.get?
      visit_location_with_turbolinks(location, turbolinks)
    else
      if request.headers["Turbolinks-Referrer"]
        store_turbolinks_location_in_session(location)
      end
    end
  end
end
like image 105
jbielick Avatar answered Jun 29 '26 12:06

jbielick