2012-04-12 62 views
16

设计一个使用before_filter :authenticate_user!来限制只有经过身份验证的用户访问。如何在AJAX中优雅地处理设计的401状态?

未经验证用户试图反正访问受限制的网页,自动设计导致重定向到登录页。

因此试图打开http://localhost:3000/users/edit将导致重定向到http://localhost:3000/users/sign_in。现在

,如果我定义链接http://localhost:3000/users/edit:remote => true,设计将只能通过JS发出401状态码

我怎样才能优雅与应对形势和显示登录对话框覆盖重定向作为非远程变量会怎么做呢?

是否提供了一个默认策略,我只需要激活该情况?

回答

12

这是我选择了现在的解决方案(在CoffeeScript的语法):

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

但是,这(在它自己的),只是忘记关于页面的用户最初想要参观,该组合限制住可用性。

需要更多(控制器)逻辑才能进行更优雅的处理。

UPDATE:正确重定向

在函数,this保持初始URL的用户打算去。

通过调用window.location.replace(this)而不是明确地重定向到登录页面),应用程序会尝试将用户重定向到最初预期的目标。

虽然还是不可能的(非法),这将现在是一个GET调用(而不是JS/AJAX)。因此设计能踢,将用户重定向到登录页面。

从那里,制定工作像往常一样,在成功注册后转发用户最初预期的URL

+0

使用此代替'window.location.replace('/ auth/login?return_to ='+ window.location.pathname);' – 2014-09-13 09:44:31

+0

我希望这个答案更好,如果它是用JavaScript编写的,而不是一些asinine的写作方式JavaScript最终被编译为JavaScript。 – Catfish 2015-12-23 02:44:27

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.

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

+1

感谢您的想法。它类似于我目前的做法,我是从这个答案有:http://stackoverflow.com/questions/5460150/devise-with-rails-3-and-remote-true ---但显然有中没有ERB支持这种情况下,它使得不可能将渲染甚至干脆重定向到'new_user_session_path'或类似的东西。 – user569825 2012-04-12 14:08:21

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值。

注意,更优雅的方式,如果你已经有一个覆盖或对话框是简单地插入一个消息,所以不是警报():

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

,并在您登入形式,你只是做一个

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

或者你甚至可以替换表格的标题,你的需求是什么。

+0

感谢您的建议。我想你明白我在示例中的登录页面。然而,问题是关于在未经认证的情况下尝试访问受限区域。请注意,'.live()'在jQuery 1.7中被弃用,赞成'.on()'。 – user569825 2012-05-05 08:26:26

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

这为我工作 - 我把它放在被调用每一个网页在那里我有Ajax提交一个js文件,但我取代了$(“选择”)HTML(xhr.responseText);}与location.reload。 ();这踢设计融入生活,重定向到正常的登录页面和登录之后让你回来 – Mitch 2013-10-15 21:05:11

+0

@米奇:是的。这就是正确的 – 2015-11-23 02:41:05

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 
     } 
    }); 
}); 

测试用设计3.1.1,这确实设置了session["user_return_to"],所以用户在再次登录()后返回到页面。

我加入了alert作为一种简单的方式来解决这里讨论的不雅信息的问题:Session Timeout Message in RoR using Devise

+0

我看不出这可以作为一个解决方法的问题就超时。但是,如果登录表单位于不同的页面上,则此代码似乎无法重定向到该页面。 – user569825 2013-10-29 23:13:29

+0

您是否认为登录表单位于与标准页面不同的页面上?我没有尝试过。 '耙路线| grep signin'为你返回任何东西?我会去'devise/sessions#new',我认为这是默认的(尽管我已经明确地为其他原因定义了它)。所有这些代码所做的是重新加载基本页面,这应该强制设计为“**重定向,因为非远程变体**会这样做。“ – 2013-10-31 00:44:41

+1

问题是,如果用户”当前“发现自己在允许未经身份验证访问的页面上,但点击了指向**的页面的链接,**需要他进行身份验证,则提议的解决方案只是重新加载当前的,已经可访问的**(!)**页面,Devise对于Devise来说是不可见的,会话#new(或类似的)是不变的为了覆盖这两种情况,你应该重定向到预期的页面。请看我的答案中的'location.replace' – user569825 2013-11-05 22:50:05

2

这里是CoffeScript我复制过去,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 %>' 
    } 
}); 
相关问题