如何在AJAX中优雅地处理设计401的状态?

设计使用before_filter :authenticate_user! 仅限制对经过身份validation的用户的访问。

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

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

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

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

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

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

这是我现在选择的解决方案(在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。

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作为解决此处讨论的不良消息问题的简单方法: 使用Devise在RoR中的会话超时消息

这是我在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 %>' } }); 

如果您正在执行“: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'); 

并以你的签名forms,你只需要做一个

 

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

我很高兴看到有一种优雅的方式来做到这一点!

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

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

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