我有一个带有Devise和CanCan的Rails 3.1(RC5)应用程序。两者都配置良好并按预期工作,除了当我运行集成测试以确保根据需要重定向AccessDenied时,重定向转到Devise的登录而不是应用程序根。我可以在测试中验证用户是否仍然登录并仍然可以访问应用程序的适用部分。
重定向在此短控制器中定义,其他受限制的控制器继承该控制器(而不是直接继承ApplicationController)。
class AuthorizedController < ApplicationController
before_filter :authenticate_user!
rescue_from CanCan::AccessDenied do |exception|
redirect_to root_url, :alert => exception.message
end
end
受限制的控制器如下所示:
class Admin::UsersController < AuthorizedController
load_and_authorize_resource
def index
@users = User.all.order('name')
end
...
end
我正在使用默认(ActionDispatch :: IntegrationTest)集成测试;我拥有的唯一额外测试宝石是Capybara,Machinist和Faker(没有RSpec,Cucumber等)。
我的测试看起来像:
def test_user_permissions
sign_in users(:user)
get admin_users_path
assert_response :redirect
assert_redirected_to root_url
end
测试失败了:
Expected response to be a redirect to <http://www.example.com/> but was a redirect to <http://www.example.com/users/sign_in>
当我在开发环境中以限制用户身份登录进行测试时,我按预期重定向到'/',但在集成测试中使用相同类型的用户失败。
在集成测试中,用户实际上并未注销,尽管重定向使其看起来正在发生。当我将测试更改为不测试重定向目标并继续尝试其他URL时,用户仍然登录并且测试通过。
我最初没有包含持有关键线索的sign_in方法。这是:
module ActionController
class IntegrationTest
include Capybara::DSL
def sign_in (user, password = 'Passw0rd')
sign_out
visit root_path
fill_in 'Email', :with => user.email
fill_in 'Password', :with => password
click_button 'Sign in'
signed_in? user
end
...
end
end
我在测试visit
和vanilla集成测试访问方法(click_button
等)中混合了Capybara访问方法(sign_in
,get
等) 。当我使用Webrat(在Capybara之前)时,这种混合按照我的预期工作,但显然Capybara的会话状态是单独处理的,因此通过Capybara方法的访问被验证,但是通过vanilla集成测试方法访问不是。
答案 0 :(得分:1)
您没有在ApplicationController中发布您的设计配置,但看起来设计身份/登录检查在CanCan授权检查之前加载(这是有意义的)。
看起来您的测试登录设置无法正常工作,因为当没有有效的用户会话时,'/ users / sign_in'是设计的默认重定向。
由于设计身份检查失败,因此它永远不会进入您的CanCan授权检查。如果还没有用户,为什么要问用户可以做什么。
before_filters将按照它们定义的顺序首先从基础ApplicationController执行,因此子类过滤后的子类过滤器。这就是为什么我认为你的基础ApplicationController中有Devise配置导致它不能命中CanCan。
如果你发布你的Devise配置/代码,我们可能会帮助你进一步调试它。
EDIT / TLDR:
您正在看到重定向登录,因为Devise认为不存在有效的用户会话。您的测试“sign_in()”帮助程序无法按您认为的那样工作。这就是为什么它在开发模式下通过手动登录进行实时用户会话。