Rails не перезагружает сессию на ajax-сообщении

У меня возникла очень странная проблема с Rails и ajax с помощью jQuery (хотя я не думаю, что это специфично для jQuery).

Приложение My Rails использует хранилище сеансов cookie, и у меня очень простой вход, который устанавливает идентификатор пользователя в сеансе. Если user_id не задан в сеансе, он перенаправляется на страницу входа. Это работает без проблем. Запросы JQuery GET также работают отлично. Проблема в том, что когда я выполняю JQuery POST - браузер отправляет cookie сессии в порядке (я подтвердил это с помощью Firebug и сбросил request.cookies в журнал), но сеанс пуст, то есть сеанс {}.

Я делаю это в своем приложении application.js:

$(document).ajaxSend(function(e, xhr, options) {
  var token = $("meta[name='csrf-token']").attr('content');
  xhr.setRequestHeader('X-CSRF-Token', token);
});

и вот мой пример:

$.post('/test/1', { _method: 'delete' }, null, 'json');

который должен перейти к этому методу контроллера (_method: delete):

def destroy
  respond_to do |format|
    format.json { render :json => { :destroyed => 'ok' }.to_json }
  end
end

Глядя на журнал и используя Firebug, я могу подтвердить, что правильное значение cookie отправляется в заголовке запроса при возникновении сообщения ajax, но кажется, что в какой-то момент Rails теряет это значение и, следовательно, теряет сеанс, поэтому он перенаправляет на страницу входа в систему и никогда не попадает в этот метод.

Я пробовал все, что мог придумать, чтобы отладить это, но я прихожу к идее, что это может быть ошибка в Rails. Я использую Rails 3.0.4 и jQuery 1.5, если это помогает. Мне очень странно, что регулярные (т.е. Не-ajax) запросы get и post работают, а ajax получает запросы без проблем, это просто сообщения ajax, которые этого не делают.

Любая помощь в попытке исправить это будет очень признательна!

Большое спасибо,
Dave

Ответ 1

Я собираюсь ответить на свой вопрос, поскольку мне удалось выяснить, что происходит. Я отправлю его здесь, если он будет полезен кому-либо еще!

После дальнейшего изучения я выяснил, что код, который должен был устанавливать заголовок запроса с помощью токена CSRF, не был. Это был исходный код:

$(document).ajaxSend(function(e, xhr, options) {
  var token = $("meta[name='csrf-token']").attr('content');
  xhr.setRequestHeader('X-CSRF-Token', token);
});

Что происходит, так это то, что этот код не устанавливал заголовок, Rails получал Ajax-запрос, токен не совпал и он сбросил сеанс. Это использовалось для повышения ошибки ActionController:: InvalidAuthenticityToken (я полагаю, я бы это поймал раньше, если возникла ошибка... ну, но, так как Rails 3.0.4 теперь просто спокойно перезапускает сеанс.

Итак, чтобы отправить токен в заголовок, вы должны это сделать (большое спасибо этот чудесный пост в блоге):

$.ajaxSetup({
  beforeSend: function(xhr) {
    xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'));
  }
}); 

И теперь все работает так, как должно. Что приятно.

Ответ 2

Я нашел другой случай:

Установили ли вы 'csrf_meta_tag' в файле макета приложения?

в моем случае, я не установил этот тег и встретил ту же проблему с вашей.

И после установки csrf_meta_tag в app/views/layouts/application.html.erb, все работает отлично!

Наконец, спасибо, что помогли мне найти причину! Большое спасибо ~

Ответ 3

Это то, что официальный jquery-ujs rails adapter для серии 3.0. Вы должны помнить, что он обновляется при обновлении версий рельсов.

Для меня обновление с 3.0.3 до 3.0.8.rc4 означало также вручную извлечение файла src/rails.js из связанного репо.

Так как Rails 3.1, наконец, переключился на jQuery, вещи должны автоматически обновляться в будущем через jquery-rails gem при обновлении рельсов (и с использованием встроенного конвейера активов)