使用设计,只需使用before_filter :authenticate_user!
来限制对经过身份验证的用户的访问。
当未经身份验证的用户尝试访问受限制的页面时,设计会自动导致重定向到登录页面。
因此,尝试打开http://localhost:3000/users/edit会导致重定向到http://localhost:3000/users/sign_in。
现在,如果我将链接http://localhost:3000/users/edit定义为:remote => true
,设计只会通过JS发出 401状态代码。
我如何优雅地应对这种情况并在覆盖或重定向中显示登录对话框,因为非远程变体会这样做?
设计是否为我需要激活的情况提供默认策略?
答案 0 :(得分:15)
$(document).ajaxError(function (e, xhr, settings) {
if (xhr.status == 401) {
$('.selector').html(xhr.responseText);
}
});
答案 1 :(得分: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像往常一样运作,在成功登录后将用户转发到最初的目标网址。
答案 2 :(得分: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
作为解决此处讨论的不良信息问题的简单方法:Session Timeout Message in RoR using Devise
答案 3 :(得分: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 %>'
}
});
答案 4 :(得分:1)
如果您执行“:remote =&gt; 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>
或者你甚至可以直接替换表格的标题,无论你需要什么。
答案 5 :(得分:1)
从Rails 5.1和新的rails-ujs开始,所有自定义事件仅返回一个参数:event
。在此参数中,还有一个附加属性detail
,其中包含一组附加参数。参数data
,status
,xhr
已捆绑到event.detail
中。因此,使用ajax:error
事件处理ajax中的401错误变为:
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
}
})
答案 6 :(得分: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,它将查看响应的状态代码并重定向到登录页面。
我想知道是否有办法直接在控制器级别处理这个问题。