Rails Pundit 策略规范测试因 NoMethodError 而失败
Rails Pundit Policy Spec test failing with NoMethodError
我刚刚开始在我当前的项目中使用 Pundit 以及专家匹配器进行授权 gem。
到目前为止,它似乎对我来说通常是有效的,但我在测试中遇到了问题。
我通常尝试遵循 pundit-matchers readme and the Thunderbolt labs blog (http://thunderboltlabs.com/blog/2013/03/27/testing-pundit-policies-with-rspec/) 中的示例。
这是我的策略文件;
#app/policies/procedure_policy.rb
class ProcedurePolicy
attr_reader :user, :procedure
def initialize(user, procedure)
@user = user
@procedure = procedure
end
def index?
user.admin?
end
end
这是我的 policy_spec 文件
require 'rails_helper'
describe ProcedurePolicy do
subject {described_class.new(user, procedure)}
let(:procedure) {FactoryGirl.create(:procedure)}
context "for a guest" do
let(:user) {nil}
it {is_expected.not_to permit_action(:index)}
end
context "for a non-admin user" do
let(:user) {FactoryGirl.create(:user)}
it {is_expected.not_to permit_action(:index)}
end
context "for an admin user" do
let(:user) {FactoryGirl.create(:admin_user)}
it {is_expected.to permit_action(:index)}
end
end
我的 3 个测试中有 2 个通过; "for a non-admin user"
和 "for an admin user"
两个。 "for a guest"
测试失败
NoMethodError:
undefined method `admin?' for nil:NilClass
现在我明白为什么了。我将 nil
传递给我的 ProcedurePolicy class 的 #index?
方法,它没有 #admin?
方法。但是我在网上找到的所有示例规格都是这样做的。我没看到什么。
如果我遗漏了一些非常明显的东西,我深表歉意。我已经离开编码几年了。
Pundit 调用 current_user
方法来设置 user
,这通常由 Devise 等身份验证系统或自定义解决方案提供。这意味着在大多数情况下,期望你在达到 Pundit 逻辑之前总是有一层身份验证,所以当它到达那里时你永远不会将 user
设置为 nil。
如果您希望 Pundit 授权无需身份验证即可直接工作,则必须在策略定义中进行处理,例如:
class ProcedurePolicy
def index?
user.present? && user.admin?
end
end
"being a visitor" 上下文用于在系统中当前没有经过身份验证的用户时测试授权尝试。由于没有用户登录,因此不存在用户 record/object - 缺少 用户对象是 nil
。这就是为什么 Thunderbolt Labs 和 pundit-matchers 示例都使用 nil 来表示访问者。 nil
对象没有 admin?
方法,导致错误。
要正确处理策略中的 nil/guest 用户,请在检查用户是否为管理员之前检查用户对象是否存在,方法是直接检查用户对象或使用 present?
方法Rails,例如
def index?
user.present? && user.admin?
end
或者只是:
def index?
user && user.admin?
end
当没有用户登录时,您会发现 current_user
方法中的 Devise return nil
等身份验证系统。
我刚刚开始在我当前的项目中使用 Pundit 以及专家匹配器进行授权 gem。
到目前为止,它似乎对我来说通常是有效的,但我在测试中遇到了问题。
我通常尝试遵循 pundit-matchers readme and the Thunderbolt labs blog (http://thunderboltlabs.com/blog/2013/03/27/testing-pundit-policies-with-rspec/) 中的示例。
这是我的策略文件;
#app/policies/procedure_policy.rb
class ProcedurePolicy
attr_reader :user, :procedure
def initialize(user, procedure)
@user = user
@procedure = procedure
end
def index?
user.admin?
end
end
这是我的 policy_spec 文件
require 'rails_helper'
describe ProcedurePolicy do
subject {described_class.new(user, procedure)}
let(:procedure) {FactoryGirl.create(:procedure)}
context "for a guest" do
let(:user) {nil}
it {is_expected.not_to permit_action(:index)}
end
context "for a non-admin user" do
let(:user) {FactoryGirl.create(:user)}
it {is_expected.not_to permit_action(:index)}
end
context "for an admin user" do
let(:user) {FactoryGirl.create(:admin_user)}
it {is_expected.to permit_action(:index)}
end
end
我的 3 个测试中有 2 个通过; "for a non-admin user"
和 "for an admin user"
两个。 "for a guest"
测试失败
NoMethodError:
undefined method `admin?' for nil:NilClass
现在我明白为什么了。我将 nil
传递给我的 ProcedurePolicy class 的 #index?
方法,它没有 #admin?
方法。但是我在网上找到的所有示例规格都是这样做的。我没看到什么。
如果我遗漏了一些非常明显的东西,我深表歉意。我已经离开编码几年了。
Pundit 调用 current_user
方法来设置 user
,这通常由 Devise 等身份验证系统或自定义解决方案提供。这意味着在大多数情况下,期望你在达到 Pundit 逻辑之前总是有一层身份验证,所以当它到达那里时你永远不会将 user
设置为 nil。
如果您希望 Pundit 授权无需身份验证即可直接工作,则必须在策略定义中进行处理,例如:
class ProcedurePolicy
def index?
user.present? && user.admin?
end
end
"being a visitor" 上下文用于在系统中当前没有经过身份验证的用户时测试授权尝试。由于没有用户登录,因此不存在用户 record/object - 缺少 用户对象是 nil
。这就是为什么 Thunderbolt Labs 和 pundit-matchers 示例都使用 nil 来表示访问者。 nil
对象没有 admin?
方法,导致错误。
要正确处理策略中的 nil/guest 用户,请在检查用户是否为管理员之前检查用户对象是否存在,方法是直接检查用户对象或使用 present?
方法Rails,例如
def index?
user.present? && user.admin?
end
或者只是:
def index?
user && user.admin?
end
当没有用户登录时,您会发现 current_user
方法中的 Devise return nil
等身份验证系统。