简体   繁体   中英

Ruby On Rails before_filter called twice?

When I send an ajax request to my ruby controller, the before_filter function seems to be called twice for each ajax request. I use the before_filter for authentication.

The ajax request I use :

 $.ajax({
    type: 'GET',
    url: 'URL_TO__RoR_Controller',
    username: username,
    password: password,
    contentType: "application/json; charset=utf-8",
    success: function(data){
      console.log(data);
    },
    error: function(xhr, ajaxOptions, thrownError) {
      console.log(arguments);
    }
  });

The RoR code :

class Api::MyController < ApplicationController
before_filter :authenticate
attr_reader :current_user

def authenticate
print "===================================\n"
authenticate_or_request_with_http_basic do |username, password|
  print "\n--------------------------------\n"
  print username, password
  print "\n--------------------------------\n"
  @current_user = User.authenticate(username, password)
  print "===================================\n"
end
end

def show
 print "=================IN SHOW=================="
end
end

The RoR response to the ajax request :

Started GET "URL_TO__RoR_Controller" for 127.0.0.1 at 2015-10-08 10:18:18 +0200
Processing by Api::MyController#show as JSON
  Parameters: {"id"=>"show", "test"=>{}}
===================================
===================================
Filter chain halted as :authenticate rendered or redirected
Completed 401 Unauthorized in 1ms (ActiveRecord: 1.0ms)


Started GET "URL_TO__RoR_Controller" for 127.0.0.1 at 2015-10-08 10:18:19 +0200
Processing by Api::MyController#show as JSON
  Parameters: {"id"=>"show", "test"=>{}}
===================================

--------------------------------
USERPASS
--------------------------------
  User Load (0.2ms)  SELECT `users`.* FROM `users` WHERE `users`.`authorized` = 1 AND `users`.`login` = 'USER' LIMIT 1
===================================
=================IN SHOW==================
  Rendered URL_TO__RoR_Controller/show.json.rabl (0.8ms)
Completed 200 OK in 30ms (Views: 3.4ms | ActiveRecord: 1.7ms)

RoR config/routes.rb for this single controller :

Api::Application.routes.draw do
 namespace :api, defaults: { format: :json } do
      resources :MyController, only: [:show]
  end
 end

So basically the authenticate function seems to be executed twice for each ajax request I send. The first time authentication seems to fail. It doesn't even get in the authenticate_or_request_with_http_basic function. The second time everything seems fine.

Obviously this is not the desired behaviour. What is causing this problem?

Edit:

Okay here are my findings when removing the before_filter:

1) When Removing the before_filter completely the issue doesn't occur anymore.

2) When keeping/using the before_filter but replacing the authenticate_or_request_with_http_basic with 'true' like this:

def authenticate
 true
end 

the issue doesn't occur either. So the issue seems to be caused by authenticate_or_request_with_http_basic?

This won't happen unless it's invoked somehow.

And seeing that the requests are sent 1 second between each other, it suggests that your Ajax is being sent twice:

127.0.0.1 at 2015-10-08 10:18:18 +0200
127.0.0.1 at 2015-10-08 10:18:19 +0200

Whilst this is not an answer in itself, there are a number of things you can do to "debug" it:

  1. Firstly, you must understand this will not happen on its own
  2. The "debug" process is simply a case of identifying what's happening & resolving it
  3. I don't think Rails will fire a controller action twice without it being invoked

Thus, you have to look at the various elements of the problem:


Firstly, your Ajax request seems to be fired twice.

You've provided the following code:

$.ajax({
    type: 'GET',
    url: 'URL_TO__RoR_Controller',
    username: username,
    password: password,
    contentType: "application/json; charset=utf-8",
    success: function(data){
      console.log(data);
    },
    error: function(xhr, ajaxOptions, thrownError) {
      console.log(arguments);
    }
});

This does not show us how it's bound to the elements on your page. I'd speculate that you're running into issues with Turbolinks.

The first step to debug is to ensure that your JS binding is not impeded. Specifically, you want to make sure you're taking advantage of the turbolinks hooks ( page:load ):

#app/assets/javascripts/application.js
bind = function() {
   $(".element").on("click", function() {
      // Ajax
   });
};
$(document).on("ready page:load", bind);

Or you could delegate from the document:

#app/assets/javascripts/application.js
$(document).on("click", ".element", function() {
     // Ajax
});

Secondly, your controller actions appear to be invoked twice, but it's not just the before_filter ... it's the whole flow (in the second instance).

Filter chain halted as :authenticate rendered or redirected
Completed 401 Unauthorized in 1ms (ActiveRecord: 1.0ms)

The only reason the first before_filter didn't fire was because you weren't authenticated. I don't know how you're authenticating users, but if you were able to do it, I would think that the flow would happen.

So the question then becomes how are you getting the first request bounced ?

If you're doing anything differently between the two requests, we need to see it. Not that I think you'd know, it's doing it automatically :)

--

This could be backed up by observing the "network" requests sent to the server with the ajax:

在此处输入图片说明


Finally, you want to do some tests without the before_filter method to see if that will work. Perhaps you've not got the correct authenticity tokens or another issue within the middleware.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM