21

使用设计一种方法before_filter :authenticate_user!来限制仅对经过身份验证的用户的访问。

当未经身份验证的用户无论如何都尝试访问受限页面时,设计会自动导致重定向到登录页面。

因此,尝试打开http://localhost:3000/users/edit将导致重定向到http://localhost:3000/users/sign_in

现在,如果我将链接http://localhost:3000/users/edit定义为:remote => true,devise 只会通过 JS发出401 状态码。

我怎样才能优雅地应对这种情况并在覆盖重定向中显示登录对话框,因为非远程变体会这样做?

设计是否为我只需要激活的那种情况提供默认策略?

4

7 回答 7

16
$(document).ajaxError(function (e, xhr, settings) {
        if (xhr.status == 401) {
           $('.selector').html(xhr.responseText);
        }
    });
于 2012-07-03T09:13:23.440 回答
12

这是我现在选择的解决方案(使用 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能够启动并将用户重定向到登录页面。

从那时起,Devise 照常运行,在成功登录后将用户转发到最初预期的 URL。

于 2012-05-05T08:11:43.290 回答
2

一个版本混合事件绑定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 中的会话超时消息

于 2013-10-29T00:43:53.373 回答
2

这是我在 CoffeScript 中的 copy-past-hapy(tm) 解决方案。它将所有 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 %>'
  }
});
于 2015-06-24T15:17:28.963 回答
2

As of Rails 5.1 and the new rails-ujs, all custom events return only one parameter: event. In this parameter, there is an additional attribute detail which contains an array of extra parameters. The parameters data, status, xhr have been bundled into event.detail. So handling the 401 error in ajax with the ajax:error event becomes:

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
  }
})
于 2019-08-27T05:40:53.263 回答
1

如果您正在执行“:remote => true”,则可以在“ajax:error”事件绑定上使用 .live。

$('#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”将是表单 ID 值。

请注意,如果您已经有叠加层或对话框,更优雅的方法是简单地插入一条消息,而不是 alert():

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

在您的登录表单中,您只需执行

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

或者您甚至可以只替换表单的标题,无论您需要什么。

于 2012-05-05T00:21:08.277 回答
0

我很乐意看看是否也有一种优雅的方式来做到这一点!

在那之前,这就是我的处理方式。

在您的 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,则重定向到登录页面。

我想知道是否没有办法直接在控制器级别处理这个问题。

于 2012-04-12T13:59:46.833 回答