Как я могу элегантно управлять дизайном 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
}
})