Как я могу элегантно управлять дизайном 401 статуса в AJAX?

С помощью devise используется before_filter :authenticate_user! для ограничения доступа только к проверенным пользователям.

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

Поэтому попытка открыть http://localhost:3000/users/edit приведет к перенаправлению на http://localhost:3000/users/sign_in.

Теперь, если я определяю ссылку http://localhost:3000/users/edit как :remote => true, при разработке будет выдан код состояния 401 через JS.

Как я могу изящно справиться с этой ситуацией и отобразить диалоговое окно входа в перенаправление наложения OR , так как не удаленный вариант сделал бы это?

Предлагает ли разработчик стратегию по умолчанию для этой ситуации, которую мне просто нужно активировать?

Ответы

Ответ 1

Это решение, которое я выбрал сейчас (в синтаксисе CoffeeScript):

$ ->
  $("a").bind "ajax:error", (event, jqXHR, ajaxSettings, thrownError) ->
    if jqXHR.status == 401 # thrownError is 'Unauthorized'
      window.location.replace('/users/sign_in')

Однако это (по его собственному) просто забывает о странице, которую пользователь хотел посетить первоначально, что ограничивает удобство использования.

Для более элегантного управления требуется дополнительная (контрольная) логика.

ОБНОВЛЕНИЕ: правильное перенаправление

Внутри функции this содержит начальный URL, на который пользователь должен был перейти.

Вызвав window.location.replace(this) (вместо явного перенаправления на страницу знака), приложение попытается перенаправить пользователя к первоначально назначенному месту назначения.

Хотя все еще невозможно (неавторизованный), теперь это будет GET-вызов (вместо JS/AJAX). Поэтому Разработать можно нажать и перенаправить пользователя на страницу входа.

Оттуда, Devise работает как обычно, перенаправляя пользователя к первоначально намеченному URL после успешного входа.

Ответ 2

$(document).ajaxError(function (e, xhr, settings) {
        if (xhr.status == 401) {
           $('.selector').html(xhr.responseText);
        }
    });

Ответ 3

Связывание события смешивания версии с location.reload():

$(function($) {
  $("#new-user")
    .bind("ajax:error", function(event, xhr, status, error) {
      if (xhr.status == 401) {  // probable Devise timeout
        alert(xhr.responseText);
        location.reload();      // reload whole page so Devise will redirect to signin
      }
    });
});

Тестирование с помощью Devise 3.1.1, это правильно устанавливает session["user_return_to"], поэтому пользователь возвращается на страницу после входа в систему снова().

Я добавил alert как простой способ решения проблемы неэлегантного сообщения, обсуждаемой здесь: Сообщение о тайм-ауте сеанса в RoR с помощью программы разработки

Ответ 4

Вот мое решение copy-past-hapy (tm) в CoffeScript. Он перенаправляет все 401 на страницу входа.

<% environment.context_class.instance_eval { include Rails.application.routes.url_helpers } %>

$(document).ajaxError (_, xhr)->
  window.location = '<%= new_user_session_path %>' if xhr.status == 401

и в Javascript:

<% environment.context_class.instance_eval { include Rails.application.routes.url_helpers } %>

$(document).ajaxError( function(event, xhr){
  if (xhr.status == 401) {
    window.location = '<%= new_user_session_path %>'
  }
});

Ответ 5

Вы можете использовать .live в привязке события "ajax: error", если вы делаете ": remote = > true".

$('#member_invite, #new_user')
        .live("ajax:success", function(evt, data, status, xhr){
          $.colorbox.close();
        })
        .live("ajax:error", function(evt, data, status, xhr){
          alert("got an error");
        });

где "#new_user" будет значением идентификатора формы.

Обратите внимание, что более элегантный способ, если у вас уже есть наложение или диалог, - это просто вставить сообщение, поэтому вместо alert():

$('.messages').html('Invalid email or password');

и в вашей форме вы просто делаете

<div class="messages"></div>

Или вы могли бы просто заменить название формы, каковы ваши потребности.

Ответ 6

Я был бы рад узнать, есть ли элегантный способ сделать это!

До тех пор, вот как я справился с этим.

В вашем файле редактирования edit.js.erb вы можете поместить следующий код:

<% case response.status
  when 200
%>
  //do what you need to do
<% when 401 %>
  //handle the 401 case, for example by redirecting to root or something
  window.location.href('/');
<% else %>
  //catch all
  alert('We\'ve had a problem, please close this, refresh the page and try again');
<% end %>

Он будет смотреть код состояния ответа и перенаправлять на страницу входа, если он равен 401.

Интересно, нет ли способа справиться с этим прямо на уровне контроллера.

Ответ 7

Начиная с Rails 5.1 и новых rails-ujs, все пользовательские события возвращают только один параметр: event. В этом параметре есть дополнительный атрибут detail, который содержит массив дополнительных параметров. Параметры data, status, xhr объединены в event.detail. Таким образом, обработка ошибки 401 в ajax с событием ajax:error становится такой:

document.body.addEventListener('ajax:error', function(event) {
  var detail = event.detail;
  var response = detail[0], status = detail[1], xhr = detail[2];
  if (xhr.status == 401) {
    // handle error
  }
})